examples: cleanup (#57845)
Remove examples that were linking to just READMEs, or outdated / discontinued ones.
36
examples/amp-first/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,85 +0,0 @@
|
||||||
# AMP First Boilerplate ⚡
|
|
||||||
|
|
||||||
This example sets up the boilerplate for an AMP First Site. You can see a [live version here](https://my-next-app.sebastianbenz.vercel.app). The boilerplate includes the following features:
|
|
||||||
|
|
||||||
- AMP Extension helpers (`amp-state`, `amp-script`, ...)
|
|
||||||
- AMP Serviceworker integration
|
|
||||||
- App manifest
|
|
||||||
- Offline page
|
|
||||||
|
|
||||||
## 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/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/amp-first&project-name=amp-first&repository-name=amp-first)
|
|
||||||
|
|
||||||
## 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 amp-first amp-first-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example amp-first amp-first-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example amp-first amp-first-app
|
|
||||||
```
|
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits. You will also see AMP validation errors in the console.
|
|
||||||
|
|
||||||
## Todo
|
|
||||||
|
|
||||||
Things you need to do after installing the boilerplate:
|
|
||||||
|
|
||||||
1. Update your app manifest in [`public/manifest.json`](public/manifest.json) with your app-specific data (`theme_color`, `background_color`, `name`, `short_name`).
|
|
||||||
2. Update the `THEME_COLOR` variable defined in [`components/Layout.js`](components/Layout.js).
|
|
||||||
3. Update favicon and icons in [`public/favicon.ico`](public/favicon.ico) and [`public/static/images/icons-*.png`](public/static/images).
|
|
||||||
4. Set the default language in [`pages/_document.js`](pages/_document.js).
|
|
||||||
5. Review the AMP Serviceworker implementation in [`public/serviceworker.js`](public/serviceworker.js).
|
|
||||||
|
|
||||||
## Tips & Tricks
|
|
||||||
|
|
||||||
- **Using AMP Components:** you can import AMP components using `next/head`. Checkout `components/amp/AmpCustomElement` for a simple way to import AMP components. Once the component is imported, you can use it like any other HTML element.
|
|
||||||
- **amp-bind & amp-state:** it's no problem to use `amp-bind` and `amp-state` with Next.js. There are two things to be aware of:
|
|
||||||
|
|
||||||
1. The `[...]` binding syntax, e.g. `[text]="myStateVariable"`, is not supported in JSX. Use `data-amp-bind-text="myStateVariable"` instead.
|
|
||||||
2. Initializing `amp-state` via JSON string is not supported in JSX:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<amp-state id="myState">
|
|
||||||
<script type="application/json">
|
|
||||||
{
|
|
||||||
"foo": "bar"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</amp-state>
|
|
||||||
```
|
|
||||||
|
|
||||||
Instead you need to use `dangerouslySetInnerHTML` to initialize the string. can use the [`/components/amp/AmpState.js`](components/amp/AmpState.js) component to see how it works. The same approach works for `amp-access` and `amp-consent` as well:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<AmpState id="message" value={ message: 'Hello World' }/>
|
|
||||||
```
|
|
||||||
|
|
||||||
- **amp-list & amp-mustache:** mustache templates conflict with JSX and it's template literals need to be escaped. A simple approach is to escape them via back ticks: `` src={`{{imageUrl}}`} ``.
|
|
||||||
- **amp-script:** you can use [amp-script](https://amp.dev/documentation/components/amp-script/) to add custom JavaScript to your AMP pages. The boilerplate includes a helper [`components/amp/AmpScript.js`](components/amp/AmpScript.js) to simplify using `amp-script`. The helper also supports embedding inline scripts. Good to know: Next.js uses [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer) under the hood, which automatically adds the needed script hashes for [inline amp-scripts](https://amp.dev/documentation/components/amp-script/#load-javascript-from-a-local-element).
|
|
||||||
|
|
||||||
## Deployment
|
|
||||||
|
|
||||||
For production builds, you need to run (the app will be build into the `.next` folder):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ yarn build
|
|
||||||
```
|
|
||||||
|
|
||||||
To start the application in production mode, run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ yarn start
|
|
||||||
```
|
|
||||||
|
|
||||||
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)).
|
|
107
examples/amp-first/amp.d.ts
vendored
|
@ -1,107 +0,0 @@
|
||||||
// Allow AMP elements to be a property on JSX.IntrinsicElements
|
|
||||||
|
|
||||||
// Only the intrinsic elements defined here will be accepted, and only with the attributes defined here
|
|
||||||
declare namespace JSX {
|
|
||||||
interface AmpImg {
|
|
||||||
alt?: string
|
|
||||||
src?: string
|
|
||||||
width?: string
|
|
||||||
height?: string
|
|
||||||
layout?: string
|
|
||||||
}
|
|
||||||
interface AmpInstallServiceWorker {
|
|
||||||
src: string
|
|
||||||
'data-iframe-src': string
|
|
||||||
layout: string
|
|
||||||
}
|
|
||||||
interface AmpState {
|
|
||||||
id?: string
|
|
||||||
children?: any
|
|
||||||
src?: string
|
|
||||||
}
|
|
||||||
interface AmpScript {
|
|
||||||
id?: string
|
|
||||||
children?: any
|
|
||||||
layout?: string
|
|
||||||
width?: string
|
|
||||||
height?: string
|
|
||||||
script?: any
|
|
||||||
src?: string
|
|
||||||
}
|
|
||||||
interface AmpCarousel {
|
|
||||||
children: React.ReactNode
|
|
||||||
layout?:
|
|
||||||
| 'fill'
|
|
||||||
| 'fixed'
|
|
||||||
| 'fixed-height'
|
|
||||||
| 'flex-item'
|
|
||||||
| 'intrinsic'
|
|
||||||
| 'nodisplay'
|
|
||||||
| 'responsive'
|
|
||||||
width: string
|
|
||||||
height: string
|
|
||||||
type: 'slides' | 'carousel'
|
|
||||||
role?: 'region' | 'list' | 'listitem'
|
|
||||||
controls?: ''
|
|
||||||
loop?: ''
|
|
||||||
autoplay?: ''
|
|
||||||
delay?: string
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
interface AmpList {
|
|
||||||
layout?:
|
|
||||||
| 'fill'
|
|
||||||
| 'fixed'
|
|
||||||
| 'fixed-height'
|
|
||||||
| 'flex-item'
|
|
||||||
| 'nodisplay'
|
|
||||||
| 'responsive'
|
|
||||||
temlate?: string
|
|
||||||
width?: string
|
|
||||||
height?: string
|
|
||||||
credentials?: 'omit' | 'include'
|
|
||||||
children: React.ReactNode
|
|
||||||
src?: string
|
|
||||||
binding?: string
|
|
||||||
}
|
|
||||||
interface IntrinsicElements {
|
|
||||||
'amp-img': AmpImg
|
|
||||||
'amp-install-serviceworker': AmpInstallServiceWorker
|
|
||||||
'amp-state': AmpState
|
|
||||||
'amp-script': AmpScript
|
|
||||||
'amp-carousel': AmpCarousel
|
|
||||||
'amp-list': AmpList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only the intrinsic elements defined here will be accepted, attributes don't matter
|
|
||||||
// declare namespace JSX {
|
|
||||||
// interface IntrinsicElements {
|
|
||||||
// 'amp-img': any
|
|
||||||
// 'amp-install-serviceworker': any
|
|
||||||
// 'amp-state': any
|
|
||||||
// 'amp-script': any
|
|
||||||
// 'amp-carousel': any
|
|
||||||
// 'amp-list': any
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// All intrinsic elements will be accepted
|
|
||||||
// declare namespace JSX {
|
|
||||||
// interface IntrinsicElements {
|
|
||||||
// [elemName: string]: any
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Allow custom AMP attributes on HTML elements
|
|
||||||
declare namespace React {
|
|
||||||
interface ScriptHTMLAttributes {
|
|
||||||
target?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HTMLAttributes {
|
|
||||||
submitting?: string
|
|
||||||
type?: string
|
|
||||||
on?: string
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
import Head from 'next/head'
|
|
||||||
import { AmpIncludeAmpInstallServiceworker } from './amp/AmpCustomElement'
|
|
||||||
|
|
||||||
// Your app's theme color
|
|
||||||
const THEME_COLOR = '#005af0'
|
|
||||||
|
|
||||||
type LayoutProps = {
|
|
||||||
title: string
|
|
||||||
children?: React.ReactNode
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sample page layout installing the AMP Serviceworker by default.
|
|
||||||
*/
|
|
||||||
const Layout: React.FC<LayoutProps> = ({ title, children, description }) => (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>{title || ''}</title>
|
|
||||||
<meta name="description" content={description || ''} />
|
|
||||||
<meta name="theme-color" content={THEME_COLOR} />
|
|
||||||
<link rel="icon" sizes="192x192" href="/static/images/icons-192.png" />
|
|
||||||
<link rel="apple-touch-icon" href="/static/images/icons-192.png" />
|
|
||||||
<link rel="icon" href="/static/favicon.ico" />
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
{children}
|
|
||||||
|
|
||||||
<AmpIncludeAmpInstallServiceworker />
|
|
||||||
<amp-install-serviceworker
|
|
||||||
src="/serviceworker.js"
|
|
||||||
data-iframe-src="/install-serviceworker.html"
|
|
||||||
layout="nodisplay"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style jsx global>{`
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
||||||
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
|
||||||
'Segoe UI Symbol';
|
|
||||||
min-height: 100vh;
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
text-rendering: optimizeSpeed;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default Layout
|
|
|
@ -1,535 +0,0 @@
|
||||||
/**
|
|
||||||
* @file An AMP Component import helper. This file is auto-generated using
|
|
||||||
* https://www.npmjs.com/package/@ampproject/toolbox-validator-rules.
|
|
||||||
*/
|
|
||||||
import Head from 'next/head'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
name: string
|
|
||||||
version: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeCustomElement(props: Props) {
|
|
||||||
return (
|
|
||||||
<Head>
|
|
||||||
<script
|
|
||||||
async
|
|
||||||
custom-element={props.name}
|
|
||||||
src={
|
|
||||||
'https://cdn.ampproject.org/v0/' +
|
|
||||||
props.name +
|
|
||||||
'-' +
|
|
||||||
props.version +
|
|
||||||
'.js'
|
|
||||||
}
|
|
||||||
key={props.name}
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeCustomTemplate(props: Props) {
|
|
||||||
return (
|
|
||||||
<Head>
|
|
||||||
<script
|
|
||||||
async
|
|
||||||
custom-template={props.name}
|
|
||||||
src={
|
|
||||||
'https://cdn.ampproject.org/v0/' +
|
|
||||||
props.name +
|
|
||||||
'-' +
|
|
||||||
props.version +
|
|
||||||
'.js'
|
|
||||||
}
|
|
||||||
key={props.name}
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmp3dGltf() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-3d-gltf" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmp3qPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-3q-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAccessLaterpay() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-access-laterpay" version="0.2" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAccessPoool() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-access-poool" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAccessScroll() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-access-scroll" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAccess() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-access" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAccordion() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-accordion" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpActionMacro() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-action-macro" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAdCustom() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-ad-custom" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAd() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-ad" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAddthis() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-addthis" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAnalytics() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-analytics" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAnim() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-anim" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAnimation() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-animation" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpApesterMedia() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-apester-media" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAppBanner() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-app-banner" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAudio() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-audio" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAutoAds() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-auto-ads" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpAutocomplete() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-autocomplete" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBaseCarousel() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-base-carousel" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBeopinion() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-beopinion" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBind() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-bind" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBodymovinAnimation() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-bodymovin-animation" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBridPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-brid-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBrightcove() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-brightcove" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpBysideContent() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-byside-content" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpCallTracking() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-call-tracking" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpCarousel() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-carousel" version="0.2" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpConnatixPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-connatix-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpConsent() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-consent" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDailymotion() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-dailymotion" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDateCountdown() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-date-countdown" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDateDisplay() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-date-display" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDatePicker() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-date-picker" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDelightPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-delight-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpDynamicCssClasses() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-dynamic-css-classes" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpEmbedlyCard() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-embedly-card" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpExperiment() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-experiment" version="1.0" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFacebookComments() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-facebook-comments" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFacebookLike() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-facebook-like" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFacebookPage() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-facebook-page" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFacebook() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-facebook" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFitText() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-fit-text" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFont() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-font" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpForm() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-form" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFxCollection() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-fx-collection" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpFxFlyingCarpet() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-fx-flying-carpet" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpGeo() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-geo" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpGfycat() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-gfycat" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpGist() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-gist" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpGoogleDocumentEmbed() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-google-document-embed" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpHulu() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-hulu" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpIframe() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-iframe" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpImaVideo() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-ima-video" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpImageLightbox() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-image-lightbox" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpImageSlider() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-image-slider" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpImgur() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-imgur" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpInputmask() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-inputmask" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpInstagram() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-instagram" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpInstallServiceworker() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-install-serviceworker" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpIzlesene() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-izlesene" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpJwplayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-jwplayer" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpKalturaPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-kaltura-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpLightboxGallery() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-lightbox-gallery" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpLightbox() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-lightbox" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpLinkRewriter() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-link-rewriter" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpMustache() {
|
|
||||||
return <AmpIncludeCustomTemplate name="amp-mustache" version="0.2" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpList() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AmpIncludeAmpMustache />
|
|
||||||
<AmpIncludeCustomElement name="amp-list" version="0.1" />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpLiveList() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-live-list" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpMathml() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-mathml" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpMegaphone() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-megaphone" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpMinuteMediaPlayer() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-minute-media-player" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpMowplayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-mowplayer" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpNextPage() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-next-page" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpNexxtvPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-nexxtv-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpO2Player() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-o2-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpOoyalaPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-ooyala-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpOrientationObserver() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-orientation-observer" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpPanZoom() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-pan-zoom" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpPinterest() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-pinterest" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpPlaybuzz() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-playbuzz" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpPositionObserver() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-position-observer" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpPowrPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-powr-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpReachPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-reach-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpRecaptchaInput() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-recaptcha-input" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpReddit() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-reddit" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpRiddleQuiz() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-riddle-quiz" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpScript() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-script" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSelector() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-selector" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSidebar() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-sidebar" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSkimlinks() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-skimlinks" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSlides() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-slides" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSmartlinks() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-smartlinks" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSocialShare() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-social-share" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSoundcloud() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-soundcloud" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSpringboardPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-springboard-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpStickyAd() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-sticky-ad" version="1.0" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpStoryAutoAds() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-story-auto-ads" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpStory() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-story" version="1.0" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSubscriptions() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-subscriptions" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpSubscriptionsGoogle() {
|
|
||||||
return (
|
|
||||||
<AmpIncludeCustomElement name="amp-subscriptions-google" version="0.1" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpTimeago() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-timeago" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpTruncateText() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-truncate-text" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpTwitter() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-twitter" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpUserLocation() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-user-location" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpUserNotification() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-user-notification" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVideoDocking() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-video-docking" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVideoIframe() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-video-iframe" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVideo() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-video" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVimeo() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-vimeo" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVine() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-vine" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpViqeoPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-viqeo-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpVk() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-vk" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpWebPush() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-web-push" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpWistiaPlayer() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-wistia-player" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpYotpo() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-yotpo" version="0.1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmpIncludeAmpYoutube() {
|
|
||||||
return <AmpIncludeCustomElement name="amp-youtube" version="0.1" />
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
import { AmpIncludeAmpScript } from './AmpCustomElement'
|
|
||||||
|
|
||||||
type AmpScriptProps = {
|
|
||||||
id?: string
|
|
||||||
children?: React.ReactNode
|
|
||||||
layout?: string
|
|
||||||
width?: string
|
|
||||||
height?: string
|
|
||||||
script?: Function | string
|
|
||||||
src?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const generateInlineScript = (script: Function | string) => {
|
|
||||||
if (typeof script === 'function') {
|
|
||||||
return `${script.toString()}()`
|
|
||||||
}
|
|
||||||
return String(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Embeds an AMP Script by either linking to a TS `src` file or embedding inline
|
|
||||||
* AMP Script via the `script` property. The inline script hash will automatically
|
|
||||||
* be generated by AMP Optimizer.
|
|
||||||
*/
|
|
||||||
const AmpScript: React.FC<AmpScriptProps> = ({
|
|
||||||
id,
|
|
||||||
script,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AmpIncludeAmpScript />
|
|
||||||
<amp-script script={id} {...props}>
|
|
||||||
{children}
|
|
||||||
</amp-script>
|
|
||||||
{script && (
|
|
||||||
<script
|
|
||||||
id={id}
|
|
||||||
type="text/plain"
|
|
||||||
target="amp-script"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: generateInlineScript(script),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AmpScript
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { AmpIncludeCustomElement } from './AmpCustomElement'
|
|
||||||
|
|
||||||
type AmpStateProps = {
|
|
||||||
id?: string
|
|
||||||
src?: string
|
|
||||||
children?: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const AmpState: React.FC<AmpStateProps> = ({ id, src, children }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AmpIncludeCustomElement name="amp-bind" version="0.1" />
|
|
||||||
<amp-state id={id} src={src}>
|
|
||||||
{children && (
|
|
||||||
<script
|
|
||||||
type="application/json"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: JSON.stringify(children),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</amp-state>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AmpState
|
|
5
examples/amp-first/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"next": "latest",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^18.0.0",
|
|
||||||
"@types/react": "^18.0.14",
|
|
||||||
"@types/react-dom": "^18.0.5",
|
|
||||||
"typescript": "^4.7.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,260 +0,0 @@
|
||||||
import { NextPage, GetServerSideProps } from 'next'
|
|
||||||
import Layout from '../components/Layout'
|
|
||||||
import AmpState from '../components/amp/AmpState'
|
|
||||||
import AmpScript from '../components/amp/AmpScript'
|
|
||||||
import {
|
|
||||||
AmpIncludeAmpList,
|
|
||||||
AmpIncludeAmpCarousel,
|
|
||||||
} from '../components/amp/AmpCustomElement'
|
|
||||||
|
|
||||||
export const config = { amp: true }
|
|
||||||
|
|
||||||
type HomeProps = {
|
|
||||||
host: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const Home: NextPage<HomeProps> = (props) => (
|
|
||||||
<>
|
|
||||||
<Layout
|
|
||||||
title="Welcome to AMP"
|
|
||||||
description="Learn how to build an AMP First with Next.js."
|
|
||||||
>
|
|
||||||
<main>
|
|
||||||
<h1 className="title">Welcome to AMP ⚡</h1>
|
|
||||||
<p className="description">
|
|
||||||
To get started, edit <code>pages/index.js</code> and save to reload.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<section className="hero">
|
|
||||||
<a href="https://nextjs.org/learn/basics/getting-started">
|
|
||||||
<h3>Getting Started →</h3>
|
|
||||||
<p>Learn more about Next</p>
|
|
||||||
</a>
|
|
||||||
<a href="https://nextjs.org/docs/advanced-features/amp-support/introduction">
|
|
||||||
<h3>AMP Support in Next.js →</h3>
|
|
||||||
<p>Learn how to build AMP sites with Next.js</p>
|
|
||||||
</a>
|
|
||||||
<a href="https://amp.dev/documentation/components/?format=websites">
|
|
||||||
<h3>AMP Components →</h3>
|
|
||||||
<p>See which components are available.</p>
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Using AMP Components</h3>
|
|
||||||
<p>
|
|
||||||
You can import AMP components using <code>next/head</code>. Checkout{' '}
|
|
||||||
<code>components/amp/AmpCustomElement</code> for a simple way to
|
|
||||||
import AMP components. Once the component is imported, you can use
|
|
||||||
it like any other HTML element.
|
|
||||||
</p>
|
|
||||||
<AmpIncludeAmpCarousel />
|
|
||||||
<amp-carousel
|
|
||||||
type="slides"
|
|
||||||
width="800"
|
|
||||||
height="300"
|
|
||||||
layout="responsive"
|
|
||||||
>
|
|
||||||
<amp-img
|
|
||||||
src="https://unsplash.it/800/300?id=123"
|
|
||||||
layout="fill"
|
|
||||||
alt="demo image"
|
|
||||||
/>
|
|
||||||
<amp-img
|
|
||||||
src="https://unsplash.it/800/300?id=124"
|
|
||||||
layout="fill"
|
|
||||||
alt="demo image"
|
|
||||||
/>
|
|
||||||
<amp-img
|
|
||||||
src="https://unsplash.it/800/300?id=125"
|
|
||||||
layout="fill"
|
|
||||||
alt="demo image"
|
|
||||||
/>
|
|
||||||
</amp-carousel>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>amp-bind & amp-state</h3>
|
|
||||||
<p>
|
|
||||||
It's no problem to use <code>amp-bind</code> and{' '}
|
|
||||||
<code>amp-state</code> with Next.js. There are two things to be
|
|
||||||
aware of:
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
The <code>[...]</code> binding syntax{' '}
|
|
||||||
<code>[text]="myStateVariable"</code>is not supported in JSX.
|
|
||||||
Use <code>data-amp-bind-text="myStateVariable"</code> instead.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Initializing <code>amp-state</code> via JSON string is not
|
|
||||||
supported in JSX:
|
|
||||||
<pre>{`<amp-state id="myState">
|
|
||||||
<script type="application/json">
|
|
||||||
{
|
|
||||||
"message": "Hello World"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</amp-state>`}</pre>
|
|
||||||
Instead you need to use <code>dangerouslySetInnerHTML</code> to
|
|
||||||
initialize the string. can use the{' '}
|
|
||||||
<code>/components/amp/AmpState.js</code> component to see how it
|
|
||||||
works. The same approach works for <code>amp-access</code> and{' '}
|
|
||||||
<code>amp-consent</code> as well
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
Demo:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<AmpState id="myState">
|
|
||||||
<>
|
|
||||||
{{
|
|
||||||
message: 'Hello World',
|
|
||||||
}}
|
|
||||||
</>
|
|
||||||
</AmpState>
|
|
||||||
<button
|
|
||||||
on="tap:AMP.setState({
|
|
||||||
greeting: myState.message
|
|
||||||
})"
|
|
||||||
>
|
|
||||||
Click
|
|
||||||
</button>
|
|
||||||
<span data-amp-bind-text="greeting" />
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>amp-list & amp-mustache</h3>
|
|
||||||
<p>
|
|
||||||
Mustache templates conflict with JSX and it's template literals need
|
|
||||||
to be escaped. A simple approach is to escape them via back ticks:{' '}
|
|
||||||
<code>src={`{{imageUrl}}`}</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<AmpIncludeAmpList />
|
|
||||||
<amp-list
|
|
||||||
src="https://amp.dev/documentation/examples/api/photo-stream"
|
|
||||||
layout="fixed-height"
|
|
||||||
height="64"
|
|
||||||
binding="no"
|
|
||||||
>
|
|
||||||
<template type="amp-mustache">
|
|
||||||
<amp-img
|
|
||||||
src={`{{imageUrl}}`}
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
alt="demo image"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</amp-list>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>amp-script</h3>
|
|
||||||
<p>
|
|
||||||
Checkout the{' '}
|
|
||||||
<a href="https://amp.dev/documentation/components/amp-script/">
|
|
||||||
amp-script
|
|
||||||
</a>{' '}
|
|
||||||
helper here: <code>components/amp/AmpScript.js</code> for embedding
|
|
||||||
custom JavaScript.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<AmpScript
|
|
||||||
layout="container"
|
|
||||||
src={`${props.host}/static/amp-script/hello.js`}
|
|
||||||
>
|
|
||||||
<button>Hello amp-script!</button>
|
|
||||||
</AmpScript>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The helper also supports embedding inline scripts. Good to know:
|
|
||||||
Next.js uses{' '}
|
|
||||||
<a href="https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer">
|
|
||||||
AMP Optimizer
|
|
||||||
</a>{' '}
|
|
||||||
under the hood, which automatically adds the needed script hashes
|
|
||||||
for{' '}
|
|
||||||
<a href="https://amp.dev/documentation/components/amp-script/#load-javascript-from-a-local-element">
|
|
||||||
inline amp-scripts
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
<AmpScript
|
|
||||||
id="hello-world"
|
|
||||||
layout="fixed-height"
|
|
||||||
height="64"
|
|
||||||
script="
|
|
||||||
const btn = document.querySelector('button');
|
|
||||||
btn.addEventListener('click', () => {
|
|
||||||
document.body.textContent = 'Hello World!'
|
|
||||||
})"
|
|
||||||
>
|
|
||||||
<button>Hello amp-script!</button>
|
|
||||||
</AmpScript>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
</Layout>
|
|
||||||
<style jsx>{`
|
|
||||||
code,
|
|
||||||
pre {
|
|
||||||
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo,
|
|
||||||
Courier, monospace;
|
|
||||||
background: #f2f2f2;
|
|
||||||
padding: 2px 3px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 800px;
|
|
||||||
}
|
|
||||||
main > * + * {
|
|
||||||
margin: 4rem 0.5rem;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 4rem;
|
|
||||||
}
|
|
||||||
.hero {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
||||||
grid-gap: 1rem;
|
|
||||||
}
|
|
||||||
.hero > a {
|
|
||||||
display: block;
|
|
||||||
padding: 1rem;
|
|
||||||
text-align: left;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #005af0;
|
|
||||||
}
|
|
||||||
.hero h3 {
|
|
||||||
margin: 0;
|
|
||||||
color: #067df7;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.hero p {
|
|
||||||
margin: 0;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
|
|
||||||
// amp-script requires absolute URLs, so we create a property `host` which we can use to calculate the script URL.
|
|
||||||
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
|
|
||||||
const getProtocol = (req: any) => {
|
|
||||||
if (req.connection.encrypted) {
|
|
||||||
return 'https'
|
|
||||||
}
|
|
||||||
const forwardedProto = req.headers['x-forwarded-proto']
|
|
||||||
if (forwardedProto) {
|
|
||||||
return forwardedProto.split(/\s*,\s*/)[0]
|
|
||||||
}
|
|
||||||
return 'http'
|
|
||||||
}
|
|
||||||
|
|
||||||
// WARNING: This is a generally unsafe application unless you're deploying to a managed platform like Vercel.
|
|
||||||
// Be sure your load balancer is configured to not allow spoofed host headers.
|
|
||||||
return { props: { host: `${getProtocol(req)}://${req.headers.host}` } }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home
|
|
|
@ -1,12 +0,0 @@
|
||||||
import Layout from '../components/Layout'
|
|
||||||
|
|
||||||
export const config = { amp: true }
|
|
||||||
|
|
||||||
const Home = () => (
|
|
||||||
<Layout title="Offline" description="No internet connection.">
|
|
||||||
<h1>Offline</h1>
|
|
||||||
<p>Please try again later.</p>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default Home
|
|
|
@ -1,7 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<title>installing service worker</title>
|
|
||||||
<script type="text/javascript">
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.register('/serviceworker.js')
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"short_name": "My page",
|
|
||||||
"name": "My fantastic page",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/static/images/icons-192.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "192x192"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/static/images/icons-512.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"display": "standalone",
|
|
||||||
"scope": "/",
|
|
||||||
"theme_color": "#005af0",
|
|
||||||
"background_color": "#ffffff"
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
/* global importScripts, AMP_SW */
|
|
||||||
importScripts('https://cdn.ampproject.org/sw/amp-sw.js')
|
|
||||||
|
|
||||||
/*
|
|
||||||
This configures the AMP service worker to enhance network resiliency and
|
|
||||||
optimizes asset caching. This configuration will:
|
|
||||||
|
|
||||||
- Cache AMP scripts with a stale-while-revalidate strategy for a longer duration
|
|
||||||
than the default http response headers indicate.
|
|
||||||
- Cache valid visited AMP documents, and serve only in case of flaky network conditions.
|
|
||||||
- Cache and serve an offline page.
|
|
||||||
- Serve static assets with a cache first strategy.
|
|
||||||
|
|
||||||
Checkout https://github.com/ampproject/amp-sw/ to learn more about how to configure
|
|
||||||
asset caching and link prefetching.
|
|
||||||
*/
|
|
||||||
AMP_SW.init({
|
|
||||||
assetCachingOptions: [
|
|
||||||
{
|
|
||||||
regexp: /\.(png|jpg|woff2|woff|css|js)/,
|
|
||||||
cachingStrategy: 'CACHE_FIRST', // options are NETWORK_FIRST | CACHE_FIRST | STALE_WHILE_REVALIDATE
|
|
||||||
},
|
|
||||||
],
|
|
||||||
offlinePageOptions: {
|
|
||||||
url: '/offline',
|
|
||||||
assets: [],
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -1,4 +0,0 @@
|
||||||
const btn = document.querySelector('button')
|
|
||||||
btn.addEventListener('click', () => {
|
|
||||||
document.body.textContent = 'Hello World!'
|
|
||||||
})
|
|
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 9.3 KiB |
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": false,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"incremental": true
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "amp.d.ts", "**/*.ts", "**/*.tsx"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
36
examples/amp-story/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Google AMP Story
|
|
||||||
|
|
||||||
This example shows how to create an AMP page with `amp-story` using Next.js and the AMP feature.
|
|
||||||
|
|
||||||
## 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/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/amp-story&project-name=amp-story&repository-name=amp-story)
|
|
||||||
|
|
||||||
## 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 amp-story amp-story-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example amp-story amp-story-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example amp-story amp-story-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)).
|
|
75
examples/amp-story/amp.d.ts
vendored
|
@ -1,75 +0,0 @@
|
||||||
// Allow AMP elements to be a property on JSX.IntrinsicElements
|
|
||||||
|
|
||||||
// Only the intrinsic elements defined here will be accepted, and only with the attributes defined here
|
|
||||||
declare namespace JSX {
|
|
||||||
interface AmpImg {
|
|
||||||
alt: string
|
|
||||||
src: string
|
|
||||||
width?: string
|
|
||||||
height?: string
|
|
||||||
layout: string
|
|
||||||
}
|
|
||||||
interface AmpVideo {
|
|
||||||
width: string
|
|
||||||
height: string
|
|
||||||
layout: string
|
|
||||||
poster: string
|
|
||||||
children: React.ReactNode
|
|
||||||
autoplay: string
|
|
||||||
loop?: string
|
|
||||||
}
|
|
||||||
interface AmpStory {
|
|
||||||
standalone: string
|
|
||||||
title: string
|
|
||||||
publisher: string
|
|
||||||
'publisher-logo-src': string
|
|
||||||
'poster-portrait-src': string
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
interface AmpStoryPage {
|
|
||||||
id: string
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
interface AmpStoryGridLayer {
|
|
||||||
template: 'fill' | 'vertical' | 'horizontal' | 'thirds'
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
interface AmpStoryBookend {
|
|
||||||
src: string
|
|
||||||
layout?:
|
|
||||||
| 'fill'
|
|
||||||
| 'fixed'
|
|
||||||
| 'fixed-height'
|
|
||||||
| 'flex-item'
|
|
||||||
| 'intrinsic'
|
|
||||||
| 'nodisplay'
|
|
||||||
| 'responsive'
|
|
||||||
}
|
|
||||||
interface IntrinsicElements {
|
|
||||||
'amp-img': AmpImg
|
|
||||||
'amp-video': AmpVideo
|
|
||||||
'amp-story': AmpStory
|
|
||||||
'amp-story-grid-layer': AmpStoryGridLayer
|
|
||||||
'amp-story-page': AmpStoryPage
|
|
||||||
'amp-story-bookend': AmpStoryBookend
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only the intrinsic elements defined here will be accepted, attributes don't matter
|
|
||||||
// declare namespace JSX {
|
|
||||||
// interface IntrinsicElements {
|
|
||||||
// 'amp-img': any
|
|
||||||
// 'amp-video': any
|
|
||||||
// 'amp-story': any
|
|
||||||
// 'amp-story-grid-layer': any
|
|
||||||
// 'amp-story-page': any
|
|
||||||
// 'amp-story-bookend': any
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// All intrinsic elements will be accepted
|
|
||||||
// declare namespace JSX {
|
|
||||||
// interface IntrinsicElements {
|
|
||||||
// [elemName: string]: any
|
|
||||||
// }
|
|
||||||
// }
|
|
5
examples/amp-story/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"next": "latest",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^18.0.0",
|
|
||||||
"@types/react": "^18.0.14",
|
|
||||||
"@types/react-dom": "^18.0.5",
|
|
||||||
"typescript": "^4.7.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
import Head from 'next/head'
|
|
||||||
|
|
||||||
export const config = { amp: true }
|
|
||||||
|
|
||||||
const Home = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Example AMP Story in Next.js</title>
|
|
||||||
<script
|
|
||||||
async
|
|
||||||
key="amp-story"
|
|
||||||
custom-element="amp-story"
|
|
||||||
src="https://cdn.ampproject.org/v0/amp-story-1.0.js"
|
|
||||||
/>
|
|
||||||
<script
|
|
||||||
async
|
|
||||||
key="amp-video"
|
|
||||||
custom-element="amp-video"
|
|
||||||
src="https://cdn.ampproject.org/v0/amp-video-0.1.js"
|
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<amp-story
|
|
||||||
standalone=""
|
|
||||||
title="Stories in AMP - Hello World"
|
|
||||||
publisher="AMP Project"
|
|
||||||
publisher-logo-src="https://amp.dev/favicons/coast-228x228.png"
|
|
||||||
poster-portrait-src="https://amp.dev/static/samples/img/story_dog2_portrait.jpg"
|
|
||||||
poster-square-src="https://amp.dev/static/samples/img/story_dog2_square.jpg"
|
|
||||||
poster-landscape-src="https://amp.dev/static/samples/img/story_dog2_landscape.jpg"
|
|
||||||
>
|
|
||||||
{/* <!-- A story consists of one or more pages. Each page is declared by an `amp-story-page` element. Pages are designed by layering videos, images and text. Here we have a page that uses two layers. One layer filling the available space with an image and one text layer that shows a heading. --> */}
|
|
||||||
<amp-story-page id="page-1">
|
|
||||||
<amp-story-grid-layer template="fill">
|
|
||||||
<amp-img
|
|
||||||
src="https://amp.dev/static/samples/img/story_dog2.jpg"
|
|
||||||
width="720"
|
|
||||||
height="1280"
|
|
||||||
layout="responsive"
|
|
||||||
alt="Story Dog 2"
|
|
||||||
/>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
<amp-story-grid-layer template="vertical">
|
|
||||||
<h1>Hello World</h1>
|
|
||||||
<p>This is an AMP Story.</p>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
</amp-story-page>
|
|
||||||
|
|
||||||
{/* <!-- Here we have a page consisting of a video which autoplays and loops. --> */}
|
|
||||||
<amp-story-page id="page-2">
|
|
||||||
<amp-story-grid-layer template="fill">
|
|
||||||
<amp-video
|
|
||||||
autoplay=""
|
|
||||||
loop=""
|
|
||||||
width="720"
|
|
||||||
height="960"
|
|
||||||
poster="https://amp.dev/static/samples/img/story_video_dog_cover.jpg"
|
|
||||||
layout="responsive"
|
|
||||||
>
|
|
||||||
<source
|
|
||||||
src="https://amp.dev/static/samples/video/story_video_dog.mp4"
|
|
||||||
type="video/mp4"
|
|
||||||
/>
|
|
||||||
</amp-video>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
</amp-story-page>
|
|
||||||
|
|
||||||
{/* <!-- Pre-defined entry animations make it possible to create dynamic pages without videos. The length and initial delay can be customized using the `animate-in-duration` and `animate-in-delay` properties. The [animations sample](/documentation/examples/visual-effects/amp_story_animations/) shows all available animantions in action. --> */}
|
|
||||||
<amp-story-page id="animation-demo">
|
|
||||||
<amp-story-grid-layer template="fill">
|
|
||||||
<amp-img
|
|
||||||
src="https://amp.dev/static/samples/img/story_dog4.jpg"
|
|
||||||
animate-in="fly-in-top"
|
|
||||||
width="720"
|
|
||||||
height="1280"
|
|
||||||
layout="responsive"
|
|
||||||
alt="Story Dog 4"
|
|
||||||
/>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
<amp-story-grid-layer template="thirds">
|
|
||||||
<h2
|
|
||||||
animate-in="fly-in-bottom"
|
|
||||||
grid-area="lower-third"
|
|
||||||
animate-in-delay="0.4s"
|
|
||||||
>
|
|
||||||
Best walk ever!
|
|
||||||
</h2>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
</amp-story-page>
|
|
||||||
|
|
||||||
{/* <!-- Stories can use predefined layouts to style the page. Here we're using the `thirds` template. For an overview about the available layouts take a look at the [layouts sample](/documentation/examples/style-layout/amp_story_layouts/). --> */}
|
|
||||||
<amp-story-page id="layout-demo">
|
|
||||||
<amp-story-grid-layer template="thirds">
|
|
||||||
<amp-img
|
|
||||||
grid-area="upper-third"
|
|
||||||
src="https://amp.dev/static/samples/img/story_thirds_1.jpg"
|
|
||||||
width="560"
|
|
||||||
height="420"
|
|
||||||
layout="responsive"
|
|
||||||
alt="Story Thirds 1"
|
|
||||||
/>
|
|
||||||
<amp-img
|
|
||||||
grid-area="middle-third"
|
|
||||||
src="https://amp.dev/static/samples/img/story_thirds_2.jpg"
|
|
||||||
width="560"
|
|
||||||
height="420"
|
|
||||||
layout="responsive"
|
|
||||||
alt="Story Thirds 2"
|
|
||||||
/>
|
|
||||||
<amp-img
|
|
||||||
grid-area="lower-third"
|
|
||||||
src="https://amp.dev/static/samples/img/story_thirds_3.jpg"
|
|
||||||
width="560"
|
|
||||||
height="420"
|
|
||||||
layout="responsive"
|
|
||||||
alt="Story Thirds 3"
|
|
||||||
/>
|
|
||||||
</amp-story-grid-layer>
|
|
||||||
</amp-story-page>
|
|
||||||
|
|
||||||
{/* <!-- A "bookend" panel containing links to other resources will appear on the last page of your story if you include an `amp-story-bookend` that references a [bookend JSON config](/static/samples/json/bookend.json). --> */}
|
|
||||||
<amp-story-bookend
|
|
||||||
src="https://amp.dev/static/samples/json/bookend.json"
|
|
||||||
layout="nodisplay"
|
|
||||||
/>
|
|
||||||
</amp-story>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": false,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"incremental": true
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "amp.d.ts", "**/*.ts", "**/*.tsx"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
36
examples/authsignal/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,3 +0,0 @@
|
||||||
AUTHSIGNAL_SECRET=
|
|
||||||
SESSION_TOKEN_SECRET=
|
|
||||||
REDIRECT_URL=http://localhost:3000/api/finalize-login
|
|
|
@ -1,37 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,45 +0,0 @@
|
||||||
# Authsignal Passwordless Login Example
|
|
||||||
|
|
||||||
This example shows how to integrate Authsignal with Next.js in order to implement passwordless login using email magic links and server-side redirects.
|
|
||||||
|
|
||||||
The login session is managed using cookies. Session data is encrypted using [@hapi/iron](https://hapi.dev/family/iron).
|
|
||||||
|
|
||||||
A live version of this example can be found [here](https://authsignal-next-passwordless-example.vercel.app).
|
|
||||||
|
|
||||||
## 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/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/authsignal-passwordless&project-name=authsignal-passwordless&repository-name=authsignal-passwordless)
|
|
||||||
|
|
||||||
## 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 authsignal/passwordless-login authsignal-passwordless-app
|
|
||||||
# or
|
|
||||||
yarn create next-app --example authsignal/passwordless-login authsignal-passwordless-app
|
|
||||||
# or
|
|
||||||
pnpm create next-app --example authsignal/passwordless-login authsignal-passwordless-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)).
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Log in to the [Authsignal Portal](https://portal.authsignal.com) and [enable email magic links for your tenant](https://portal.authsignal.com/organisations/tenants/authenticators).
|
|
||||||
|
|
||||||
Copy the .env.local.example file to .env.local:
|
|
||||||
|
|
||||||
```
|
|
||||||
cp .env.local.example .env.local
|
|
||||||
```
|
|
||||||
|
|
||||||
Set `AUTHSIGNAL_SECRET` as your [Authsignal secret key](https://portal.authsignal.com/organisations/tenants/api).
|
|
||||||
|
|
||||||
The `SESSION_TOKEN_SECRET` is used to encrypt the session cookie. Set it to a random string of 32 characters.
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
To learn more about Authsignal take a look at the [API Documentation](https://docs.authsignal.com/).
|
|
|
@ -1,38 +0,0 @@
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #1d1d1d;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header button {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
color: #fff;
|
|
||||||
padding: 15px;
|
|
||||||
transition: background-color 0.15s, color 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
font-size: 18px;
|
|
||||||
margin: 15px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { User } from '../lib'
|
|
||||||
import styles from './dashboard.module.css'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
user: User
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Dashboard = ({ user }: Props) => {
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const logout = async () => {
|
|
||||||
await fetch('/api/logout', {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: 'same-origin',
|
|
||||||
})
|
|
||||||
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<header className={styles.header}>
|
|
||||||
<div className={styles.logo}>My Example App</div>
|
|
||||||
<button onClick={() => logout()}>Log out</button>
|
|
||||||
</header>
|
|
||||||
<div className={styles.user}>
|
|
||||||
<div>
|
|
||||||
<div className={styles.label}>Logged in as:</div>
|
|
||||||
<div>{user.email}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export * from './dashboard'
|
|
||||||
export * from './layout'
|
|
||||||
export * from './login'
|
|
|
@ -1,16 +0,0 @@
|
||||||
import Head from 'next/head'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Layout = (props: Props) => (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Authsignal Passwordless Example</title>
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
{props.children}
|
|
||||||
</>
|
|
||||||
)
|
|
|
@ -1,57 +0,0 @@
|
||||||
.login {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login label {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
color: #ababab;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login input {
|
|
||||||
outline: none;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 400;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #1d1d1d;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
padding: 0 15px;
|
|
||||||
margin: 0 0 15px 0;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login button {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: none;
|
|
||||||
background-color: #1d1d1d;
|
|
||||||
color: #fff;
|
|
||||||
padding: 0 15px;
|
|
||||||
height: 40px;
|
|
||||||
transition: background-color 0.15s, color 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login button:hover:not(:active) {
|
|
||||||
background-color: #282828;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
import styles from './login.module.css'
|
|
||||||
|
|
||||||
export const Login = () => (
|
|
||||||
<main className={styles.login}>
|
|
||||||
<h1 className={styles.title}>My Example App</h1>
|
|
||||||
<form method="POST" action="/api/login">
|
|
||||||
<label htmlFor="email">Email</label>
|
|
||||||
<input id="email" type="email" name="email" required />
|
|
||||||
<button type="submit">Log in / Sign up</button>
|
|
||||||
</form>
|
|
||||||
</main>
|
|
||||||
)
|
|
|
@ -1,5 +0,0 @@
|
||||||
import { Authsignal } from '@authsignal/node'
|
|
||||||
|
|
||||||
const secret = process.env.AUTHSIGNAL_SECRET!
|
|
||||||
|
|
||||||
export const authsignal = new Authsignal({ secret })
|
|
|
@ -1,57 +0,0 @@
|
||||||
import Iron from '@hapi/iron'
|
|
||||||
import { parse, serialize } from 'cookie'
|
|
||||||
|
|
||||||
export const COOKIE_NAME = 'session_token'
|
|
||||||
|
|
||||||
const TOKEN_SECRET = process.env.SESSION_TOKEN_SECRET!
|
|
||||||
|
|
||||||
export async function createCookieForSession(user: User) {
|
|
||||||
// Make login session valid for 8 hours
|
|
||||||
const maxAge = 60 * 60 * 8
|
|
||||||
|
|
||||||
const expires = new Date()
|
|
||||||
expires.setSeconds(expires.getSeconds() + maxAge)
|
|
||||||
|
|
||||||
const sessionData: SessionData = { user, expiresAt: expires.toString() }
|
|
||||||
|
|
||||||
const sessionToken = await Iron.seal(sessionData, TOKEN_SECRET, Iron.defaults)
|
|
||||||
|
|
||||||
const cookie = serialize(COOKIE_NAME, sessionToken, {
|
|
||||||
maxAge,
|
|
||||||
expires,
|
|
||||||
httpOnly: true,
|
|
||||||
secure: process.env.NODE_ENV === 'production',
|
|
||||||
path: '/',
|
|
||||||
sameSite: 'lax',
|
|
||||||
})
|
|
||||||
|
|
||||||
return cookie
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getSessionFromCookie(cookie: string | undefined) {
|
|
||||||
const cookies = parse(cookie ?? '')
|
|
||||||
|
|
||||||
const sessionToken = cookies[COOKIE_NAME]
|
|
||||||
|
|
||||||
if (!sessionToken) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const sessionData: SessionData = await Iron.unseal(
|
|
||||||
sessionToken,
|
|
||||||
TOKEN_SECRET,
|
|
||||||
Iron.defaults
|
|
||||||
)
|
|
||||||
|
|
||||||
return sessionData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionData {
|
|
||||||
user: User
|
|
||||||
expiresAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface User {
|
|
||||||
userId: string
|
|
||||||
email?: string
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './authsignal'
|
|
||||||
export * from './cookies'
|
|
|
@ -1,6 +0,0 @@
|
||||||
/** @type {import('next').NextConfig} */
|
|
||||||
const nextConfig = {
|
|
||||||
reactStrictMode: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = nextConfig
|
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next dev",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@authsignal/node": "^0.0.29",
|
|
||||||
"@hapi/iron": "^7.0.0",
|
|
||||||
"cookie": "^0.5.0",
|
|
||||||
"next": "latest",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-dom": "18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/cookie": "^0.5.1",
|
|
||||||
"@types/node": "18.0.3",
|
|
||||||
"@types/react": "18.2.8",
|
|
||||||
"@types/react-dom": "18.0.6",
|
|
||||||
"typescript": "4.7.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import type { AppProps } from 'next/app'
|
|
||||||
import './globals.css'
|
|
||||||
|
|
||||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
|
||||||
return <Component {...pageProps} />
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import { authsignal, createCookieForSession } from '../../lib'
|
|
||||||
|
|
||||||
// This route handles the redirect back from the Authsignal Prebuilt MFA page
|
|
||||||
export default async function finalizeLogin(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse
|
|
||||||
) {
|
|
||||||
// Only GET requests since we are handling redirects
|
|
||||||
if (req.method !== 'GET') {
|
|
||||||
return res.status(405).send({ message: 'Only GET requests allowed' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = req.query.token as string
|
|
||||||
|
|
||||||
// This step uses your secret key to validate the token returned via the redirect
|
|
||||||
// It makes an authenticated call to Authsignal to check if the magic link challenge succeeded
|
|
||||||
const { success, user } = await authsignal.validateChallenge({ token })
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
const cookie = await createCookieForSession(user)
|
|
||||||
|
|
||||||
res.setHeader('Set-Cookie', cookie)
|
|
||||||
}
|
|
||||||
|
|
||||||
res.redirect('/')
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import { authsignal } from '../../lib'
|
|
||||||
|
|
||||||
const redirectUrl =
|
|
||||||
process.env.REDIRECT_URL ?? 'http://localhost:3000/api/finalize-login'
|
|
||||||
|
|
||||||
export default async function login(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
if (req.method !== 'POST') {
|
|
||||||
return res.status(405).send({ message: 'Only POST requests allowed' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const { email } = req.body
|
|
||||||
|
|
||||||
const { url } = await authsignal.loginWithEmail({ email, redirectUrl })
|
|
||||||
|
|
||||||
res.redirect(303, url)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import { serialize } from 'cookie'
|
|
||||||
import { COOKIE_NAME } from '../../lib'
|
|
||||||
|
|
||||||
export default async function logout(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse
|
|
||||||
) {
|
|
||||||
if (req.method !== 'POST') {
|
|
||||||
return res.status(405).send({ message: 'Only POST requests allowed' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookie = serialize(COOKIE_NAME, '', { maxAge: -1, path: '/' })
|
|
||||||
|
|
||||||
res.setHeader('Set-Cookie', cookie)
|
|
||||||
res.send({ success: true })
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
||||||
'Helvetica Neue', Arial, Noto Sans, sans-serif, 'Apple Color Emoji',
|
|
||||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
||||||
}
|
|
||||||
|
|
||||||
#__next {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { GetServerSideProps } from 'next'
|
|
||||||
import { Dashboard, Layout, Login } from '../components'
|
|
||||||
import { getSessionFromCookie, User } from '../lib'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
user: User | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps<Props> = async ({
|
|
||||||
req,
|
|
||||||
}) => {
|
|
||||||
const session = await getSessionFromCookie(req.headers.cookie)
|
|
||||||
|
|
||||||
if (session && new Date(session.expiresAt) > new Date()) {
|
|
||||||
return { props: { user: session.user } }
|
|
||||||
} else {
|
|
||||||
return { props: { user: null } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function HomePage({ user }: Props) {
|
|
||||||
return <Layout>{user ? <Dashboard user={user} /> : <Login />}</Layout>
|
|
||||||
}
|
|
Before Width: | Height: | Size: 25 KiB |
|
@ -1,4 +0,0 @@
|
||||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"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"]
|
|
||||||
}
|
|
36
examples/blog-starter-typescript/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,3 +0,0 @@
|
||||||
## Deprecated
|
|
||||||
|
|
||||||
The main [blog-starter](/examples/blog-starter) example has been refactored to use TypeScript, so this example is deprecated.
|
|
36
examples/custom-server-typescript/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,3 +0,0 @@
|
||||||
## Deprecated
|
|
||||||
|
|
||||||
The main [custom-server](/examples/custom-server) example has been refactored to use TypeScript, so this example is deprecated.
|
|
36
examples/data-fetch/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,30 +0,0 @@
|
||||||
# Data fetch example
|
|
||||||
|
|
||||||
Next.js was conceived to make it easy to create universal apps. That's why fetching data
|
|
||||||
on the server and the client when necessary is so easy with Next.js.
|
|
||||||
|
|
||||||
By using `getStaticProps` Next.js will fetch data at build time from a page, and pre-render the page to static assets.
|
|
||||||
|
|
||||||
## 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/data-fetch)
|
|
||||||
|
|
||||||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/data-fetch&project-name=data-fetch&repository-name=data-fetch)
|
|
||||||
|
|
||||||
## 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 data-fetch data-fetch-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example data-fetch data-fetch-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example data-fetch data-fetch-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)).
|
|
5
examples/data-fetch/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"next": "12.3.4",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "18.7.11",
|
|
||||||
"@types/react": "18.2.8",
|
|
||||||
"typescript": "4.7.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import Link from 'next/link'
|
|
||||||
import type { InferGetStaticPropsType } from 'next'
|
|
||||||
import type { Repository } from '../types/github'
|
|
||||||
|
|
||||||
export async function getStaticProps() {
|
|
||||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
|
||||||
const data: Repository = await res.json()
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
stars: data.stargazers_count,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function IndexPage({
|
|
||||||
stars,
|
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p>Next.js has {stars} ⭐️</p>
|
|
||||||
<Link href="/preact-stars">How about preact?</Link>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import Link from 'next/link'
|
|
||||||
import type { InferGetStaticPropsType } from 'next'
|
|
||||||
import type { Repository } from '../types/github'
|
|
||||||
|
|
||||||
export async function getStaticProps() {
|
|
||||||
const res = await fetch('https://api.github.com/repos/preactjs/preact')
|
|
||||||
const json: Repository = await res.json()
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
stars: json.stargazers_count,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PreactStarsPage({
|
|
||||||
stars,
|
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p>Preact has {stars} ⭐</p>
|
|
||||||
<Link href="/">I bet Next.js has more stars (?)</Link>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": false,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve"
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
10
examples/data-fetch/types/github.d.ts
vendored
|
@ -1,10 +0,0 @@
|
||||||
// For simplicity we are creating our own types here.
|
|
||||||
// If you want the full types check out:
|
|
||||||
// https://github.com/octokit/openapi-types.ts
|
|
||||||
export type Repository = {
|
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
full_name: string
|
|
||||||
stargazers_count: number
|
|
||||||
private: boolean
|
|
||||||
} & Record<string, unknown>
|
|
36
examples/evm-multichain-dapp/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,27 +0,0 @@
|
||||||
# EVM multichain nextjs template
|
|
||||||
|
|
||||||
Nextjs Public template for building Ethereum Virtual Machine Multichain Dapps
|
|
||||||
|
|
||||||
## 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/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/evm-multichain-dapp&project-name=evm-multichain-dapp&repository-name=evm-multichain-dapp)
|
|
||||||
|
|
||||||
## 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 evm-multichain-dapp evm-multichain-dapp-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example evm-multichain-dapp evm-multichain-dapp-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example evm-multichain-dapp evm-multichain-dapp-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)).
|
|
|
@ -1,288 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "owner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "spender",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "value",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Approval",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "previousOwner",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "newOwner",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "OwnershipTransferred",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "from",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "to",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "value",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "Transfer",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "_decimals",
|
|
||||||
"outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "_name",
|
|
||||||
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "_symbol",
|
|
||||||
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "owner", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "spender", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "allowance",
|
|
||||||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "spender", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "approve",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "account", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "balanceOf",
|
|
||||||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "burn",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "decimals",
|
|
||||||
"outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "spender", "type": "address" },
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "subtractedValue",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "decreaseAllowance",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "getOwner",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "spender", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "addedValue", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "increaseAllowance",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "mint",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "name",
|
|
||||||
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "owner",
|
|
||||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "renounceOwnership",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "symbol",
|
|
||||||
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": true,
|
|
||||||
"inputs": [],
|
|
||||||
"name": "totalSupply",
|
|
||||||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "recipient", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "transfer",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "sender", "type": "address" },
|
|
||||||
{ "internalType": "address", "name": "recipient", "type": "address" },
|
|
||||||
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
|
|
||||||
],
|
|
||||||
"name": "transferFrom",
|
|
||||||
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{ "internalType": "address", "name": "newOwner", "type": "address" }
|
|
||||||
],
|
|
||||||
"name": "transferOwnership",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": false,
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,166 +0,0 @@
|
||||||
{
|
|
||||||
"1": {
|
|
||||||
"nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 },
|
|
||||||
"name": "Ethereum Mainnet"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Ropsten Ether",
|
|
||||||
"symbol": "ROP",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Ropsten"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Rinkeby Ether",
|
|
||||||
"symbol": "RIN",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Rinkeby"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Görli Ether",
|
|
||||||
"symbol": "GOR",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Görli"
|
|
||||||
},
|
|
||||||
"40": {
|
|
||||||
"nativeCurrency": { "name": "Telos", "symbol": "TLOS", "decimals": 18 },
|
|
||||||
"name": "Telos EVM Mainnet"
|
|
||||||
},
|
|
||||||
"42": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Kovan Ether",
|
|
||||||
"symbol": "KOV",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Kovan"
|
|
||||||
},
|
|
||||||
"56": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Binance Chain Native Token",
|
|
||||||
"symbol": "BNB",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Binance Smart Chain Mainnet"
|
|
||||||
},
|
|
||||||
"65": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "OKExChain Global Utility Token in testnet",
|
|
||||||
"symbol": "OKT",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "OKExChain Testnet"
|
|
||||||
},
|
|
||||||
"66": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "OKXChain Global Utility Token",
|
|
||||||
"symbol": "OKT",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "OKXChain Mainnet"
|
|
||||||
},
|
|
||||||
"97": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Binance Chain Native Token",
|
|
||||||
"symbol": "tBNB",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Binance Smart Chain Testnet"
|
|
||||||
},
|
|
||||||
"100": {
|
|
||||||
"nativeCurrency": { "name": "xDAI", "symbol": "xDAI", "decimals": 18 },
|
|
||||||
"name": "Gnosis Chain"
|
|
||||||
},
|
|
||||||
"122": {
|
|
||||||
"nativeCurrency": { "name": "Fuse", "symbol": "FUSE", "decimals": 18 },
|
|
||||||
"name": "Fuse Mainnet"
|
|
||||||
},
|
|
||||||
"128": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Huobi ECO Chain Native Token",
|
|
||||||
"symbol": "HT",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Huobi ECO Chain Mainnet"
|
|
||||||
},
|
|
||||||
"137": {
|
|
||||||
"nativeCurrency": { "name": "MATIC", "symbol": "MATIC", "decimals": 18 },
|
|
||||||
"name": "Polygon Mainnet"
|
|
||||||
},
|
|
||||||
"250": {
|
|
||||||
"nativeCurrency": { "name": "Fantom", "symbol": "FTM", "decimals": 18 },
|
|
||||||
"name": "Fantom Opera"
|
|
||||||
},
|
|
||||||
"256": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "Huobi ECO Chain Test Native Token",
|
|
||||||
"symbol": "htt",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "Huobi ECO Chain Testnet"
|
|
||||||
},
|
|
||||||
"1284": {
|
|
||||||
"nativeCurrency": { "name": "Glimmer", "symbol": "GLMR", "decimals": 18 },
|
|
||||||
"name": "Moonbeam"
|
|
||||||
},
|
|
||||||
"1285": {
|
|
||||||
"nativeCurrency": { "name": "Moonriver", "symbol": "MOVR", "decimals": 18 },
|
|
||||||
"name": "Moonriver"
|
|
||||||
},
|
|
||||||
"1287": {
|
|
||||||
"nativeCurrency": { "name": "Dev", "symbol": "DEV", "decimals": 18 },
|
|
||||||
"name": "Moonbase Alpha"
|
|
||||||
},
|
|
||||||
"4002": {
|
|
||||||
"nativeCurrency": { "name": "Fantom", "symbol": "FTM", "decimals": 18 },
|
|
||||||
"name": "Fantom Testnet"
|
|
||||||
},
|
|
||||||
"31337": {
|
|
||||||
"nativeCurrency": {
|
|
||||||
"name": "GoChain Coin",
|
|
||||||
"symbol": "GO",
|
|
||||||
"decimals": 18
|
|
||||||
},
|
|
||||||
"name": "GoChain Testnet"
|
|
||||||
},
|
|
||||||
"42161": {
|
|
||||||
"nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 },
|
|
||||||
"name": "Arbitrum One"
|
|
||||||
},
|
|
||||||
"42220": {
|
|
||||||
"nativeCurrency": { "name": "CELO", "symbol": "CELO", "decimals": 18 },
|
|
||||||
"name": "Celo Mainnet"
|
|
||||||
},
|
|
||||||
"43113": {
|
|
||||||
"nativeCurrency": { "name": "Avalanche", "symbol": "AVAX", "decimals": 18 },
|
|
||||||
"name": "Avalanche Fuji Testnet"
|
|
||||||
},
|
|
||||||
"43114": {
|
|
||||||
"nativeCurrency": { "name": "Avalanche", "symbol": "AVAX", "decimals": 18 },
|
|
||||||
"name": "Avalanche C-Chain"
|
|
||||||
},
|
|
||||||
"80001": {
|
|
||||||
"nativeCurrency": { "name": "MATIC", "symbol": "MATIC", "decimals": 18 },
|
|
||||||
"name": "Mumbai"
|
|
||||||
},
|
|
||||||
"1666600000": {
|
|
||||||
"nativeCurrency": { "name": "ONE", "symbol": "ONE", "decimals": 18 },
|
|
||||||
"name": "Harmony Mainnet Shard 0"
|
|
||||||
},
|
|
||||||
"1666700000": {
|
|
||||||
"nativeCurrency": { "name": "ONE", "symbol": "ONE", "decimals": 18 },
|
|
||||||
"name": "Harmony Testnet Shard 0"
|
|
||||||
},
|
|
||||||
"11297108109": {
|
|
||||||
"nativeCurrency": { "name": "PALM", "symbol": "PALM", "decimals": 18 },
|
|
||||||
"name": "Palm"
|
|
||||||
},
|
|
||||||
"11297108099": {
|
|
||||||
"nativeCurrency": { "name": "PALM", "symbol": "PALM", "decimals": 18 },
|
|
||||||
"name": "Palm Testnet"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
export enum ChainId {
|
|
||||||
ETHEREUM = 1,
|
|
||||||
ROPSTEN = 3,
|
|
||||||
RINKEBY = 4,
|
|
||||||
GÖRLI = 5,
|
|
||||||
KOVAN = 42,
|
|
||||||
MATIC = 137,
|
|
||||||
MATIC_TESTNET = 80001,
|
|
||||||
FANTOM = 250,
|
|
||||||
FANTOM_TESTNET = 4002,
|
|
||||||
XDAI = 100,
|
|
||||||
BSC = 56,
|
|
||||||
BSC_TESTNET = 97,
|
|
||||||
ARBITRUM = 42161,
|
|
||||||
MOONBEAM_TESTNET = 1287,
|
|
||||||
AVALANCHE = 43114,
|
|
||||||
AVALANCHE_TESTNET = 43113,
|
|
||||||
HECO = 128,
|
|
||||||
HECO_TESTNET = 256,
|
|
||||||
HARMONY = 1666600000,
|
|
||||||
HARMONY_TESTNET = 1666700000,
|
|
||||||
OKEX = 66,
|
|
||||||
OKEX_TESTNET = 65,
|
|
||||||
CELO = 42220,
|
|
||||||
PALM = 11297108109,
|
|
||||||
PALM_TESTNET = 11297108099,
|
|
||||||
MOONRIVER = 1285,
|
|
||||||
FUSE = 122,
|
|
||||||
TELOS = 40,
|
|
||||||
HARDHAT = 31337,
|
|
||||||
MOONBEAM = 1284,
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
import { ChainId } from './chainIds'
|
|
||||||
|
|
||||||
const Arbitrum =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/arbitrum.jpg'
|
|
||||||
const Avalanche =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/avalanche.jpg'
|
|
||||||
const Bsc =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/bsc.jpg'
|
|
||||||
const Fantom =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/fantom.jpg'
|
|
||||||
const Goerli =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/goerli.jpg'
|
|
||||||
const Harmony =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/harmonyone.jpg'
|
|
||||||
const Heco =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/heco.jpg'
|
|
||||||
const Kovan =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/kovan.jpg'
|
|
||||||
const Mainnet =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/mainnet.jpg'
|
|
||||||
const Matic =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/polygon.jpg'
|
|
||||||
const Moonbeam =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/moonbeam.jpg'
|
|
||||||
const OKEx =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/okex.jpg'
|
|
||||||
const Polygon =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/polygon.jpg'
|
|
||||||
const Rinkeby =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/rinkeby.jpg'
|
|
||||||
const Ropsten =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/ropsten.jpg'
|
|
||||||
const xDai =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/xdai.jpg'
|
|
||||||
const Celo =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/celo.jpg'
|
|
||||||
const Palm =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/palm.jpg'
|
|
||||||
const Moonriver =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/network/moonriver.jpg'
|
|
||||||
const Fuse =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/icons/master/token/fuse.jpg'
|
|
||||||
const Telos =
|
|
||||||
'https://raw.githubusercontent.com/sushiswap/logos/main/network/telos/0xD102cE6A4dB07D247fcc28F366A623Df0938CA9E.jpg'
|
|
||||||
|
|
||||||
export const NETWORK_ICON = {
|
|
||||||
[ChainId.ETHEREUM]: Mainnet,
|
|
||||||
[ChainId.ROPSTEN]: Ropsten,
|
|
||||||
[ChainId.RINKEBY]: Rinkeby,
|
|
||||||
[ChainId.GÖRLI]: Goerli,
|
|
||||||
[ChainId.KOVAN]: Kovan,
|
|
||||||
[ChainId.FANTOM]: Fantom,
|
|
||||||
[ChainId.FANTOM_TESTNET]: Fantom,
|
|
||||||
[ChainId.BSC]: Bsc,
|
|
||||||
[ChainId.BSC_TESTNET]: Bsc,
|
|
||||||
[ChainId.MATIC]: Polygon,
|
|
||||||
[ChainId.MATIC_TESTNET]: Matic,
|
|
||||||
[ChainId.XDAI]: xDai,
|
|
||||||
[ChainId.ARBITRUM]: Arbitrum,
|
|
||||||
[ChainId.MOONBEAM_TESTNET]: Moonbeam,
|
|
||||||
[ChainId.AVALANCHE]: Avalanche,
|
|
||||||
[ChainId.AVALANCHE_TESTNET]: Avalanche,
|
|
||||||
[ChainId.HECO]: Heco,
|
|
||||||
[ChainId.HECO_TESTNET]: Heco,
|
|
||||||
[ChainId.HARMONY]: Harmony,
|
|
||||||
[ChainId.HARMONY_TESTNET]: Harmony,
|
|
||||||
[ChainId.OKEX]: OKEx,
|
|
||||||
[ChainId.OKEX_TESTNET]: OKEx,
|
|
||||||
[ChainId.CELO]: Celo,
|
|
||||||
[ChainId.PALM]: Palm,
|
|
||||||
[ChainId.MOONRIVER]: Moonriver,
|
|
||||||
[ChainId.FUSE]: Fuse,
|
|
||||||
[ChainId.TELOS]: Telos,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NETWORK_LABEL: { [chainId in ChainId]?: string } = {
|
|
||||||
[ChainId.ETHEREUM]: 'Ethereum',
|
|
||||||
[ChainId.RINKEBY]: 'Rinkeby',
|
|
||||||
[ChainId.ROPSTEN]: 'Ropsten',
|
|
||||||
[ChainId.GÖRLI]: 'Görli',
|
|
||||||
[ChainId.KOVAN]: 'Kovan',
|
|
||||||
[ChainId.FANTOM]: 'Fantom',
|
|
||||||
[ChainId.FANTOM_TESTNET]: 'Fantom Testnet',
|
|
||||||
[ChainId.MATIC]: 'Polygon',
|
|
||||||
[ChainId.MATIC_TESTNET]: 'Polygon Testnet',
|
|
||||||
[ChainId.XDAI]: 'xDai',
|
|
||||||
[ChainId.ARBITRUM]: 'Arbitrum',
|
|
||||||
[ChainId.BSC]: 'BSC',
|
|
||||||
[ChainId.BSC_TESTNET]: 'BSC Testnet',
|
|
||||||
[ChainId.MOONBEAM_TESTNET]: 'Moonbase',
|
|
||||||
[ChainId.AVALANCHE]: 'Avalanche',
|
|
||||||
[ChainId.AVALANCHE_TESTNET]: 'Fuji',
|
|
||||||
[ChainId.HECO]: 'HECO',
|
|
||||||
[ChainId.HECO_TESTNET]: 'HECO Testnet',
|
|
||||||
[ChainId.HARMONY]: 'Harmony',
|
|
||||||
[ChainId.HARMONY_TESTNET]: 'Harmony Testnet',
|
|
||||||
[ChainId.OKEX]: 'OKEx',
|
|
||||||
[ChainId.OKEX_TESTNET]: 'OKEx',
|
|
||||||
[ChainId.CELO]: 'Celo',
|
|
||||||
[ChainId.PALM]: 'Palm',
|
|
||||||
[ChainId.MOONRIVER]: 'Moonriver',
|
|
||||||
[ChainId.FUSE]: 'Fuse',
|
|
||||||
[ChainId.TELOS]: 'Telos EVM',
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
import { ChainId } from './chainIds'
|
|
||||||
|
|
||||||
const RPC = {
|
|
||||||
[ChainId.ETHEREUM]: 'https://api.sushirelay.com/v1',
|
|
||||||
// [ChainId.ETHEREUM]: 'https://eth-mainnet.alchemyapi.io/v2/HNQXSfiUcPjfpDBQaWYXjqlhTr1cEY9c',
|
|
||||||
// [ChainId.MAINNET]: 'https://eth-mainnet.alchemyapi.io/v2/q1gSNoSMEzJms47Qn93f9-9Xg5clkmEC',
|
|
||||||
[ChainId.ROPSTEN]:
|
|
||||||
'https://eth-ropsten.alchemyapi.io/v2/cidKix2Xr-snU3f6f6Zjq_rYdalKKHmW',
|
|
||||||
[ChainId.RINKEBY]:
|
|
||||||
'https://eth-rinkeby.alchemyapi.io/v2/XVLwDlhGP6ApBXFz_lfv0aZ6VmurWhYD',
|
|
||||||
[ChainId.GÖRLI]:
|
|
||||||
'https://eth-goerli.alchemyapi.io/v2/Dkk5d02QjttYEoGmhZnJG37rKt8Yl3Im',
|
|
||||||
[ChainId.KOVAN]:
|
|
||||||
'https://eth-kovan.alchemyapi.io/v2/6OVAa_B_rypWWl9HqtiYK26IRxXiYqER',
|
|
||||||
[ChainId.FANTOM]: 'https://rpcapi.fantom.network',
|
|
||||||
[ChainId.FANTOM_TESTNET]: 'https://rpc.testnet.fantom.network',
|
|
||||||
[ChainId.MATIC]: 'https://polygon-rpc.com/',
|
|
||||||
[ChainId.MATIC_TESTNET]: 'https://rpc-mumbai.matic.today',
|
|
||||||
[ChainId.XDAI]: 'https://rpc.xdaichain.com',
|
|
||||||
[ChainId.BSC]: 'https://bsc-dataseed.binance.org/',
|
|
||||||
[ChainId.BSC_TESTNET]: 'https://data-seed-prebsc-2-s3.binance.org:8545',
|
|
||||||
[ChainId.MOONBEAM_TESTNET]: 'https://rpc.testnet.moonbeam.network',
|
|
||||||
[ChainId.AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',
|
|
||||||
[ChainId.AVALANCHE_TESTNET]: 'https://api.avax-test.network/ext/bc/C/rpc',
|
|
||||||
[ChainId.HECO]: 'https://http-mainnet.hecochain.com',
|
|
||||||
[ChainId.HECO_TESTNET]: 'https://http-testnet.hecochain.com',
|
|
||||||
[ChainId.HARMONY]: 'https://api.harmony.one',
|
|
||||||
[ChainId.HARMONY_TESTNET]: 'https://api.s0.b.hmny.io',
|
|
||||||
[ChainId.OKEX]: 'https://exchainrpc.okex.org',
|
|
||||||
[ChainId.OKEX_TESTNET]: 'https://exchaintestrpc.okex.org',
|
|
||||||
[ChainId.ARBITRUM]: 'https://arb1.arbitrum.io/rpc',
|
|
||||||
[ChainId.PALM]:
|
|
||||||
'https://palm-mainnet.infura.io/v3/da5fbfafcca14b109e2665290681e267',
|
|
||||||
[ChainId.FUSE]: 'https://rpc.fuse.io',
|
|
||||||
[ChainId.CELO]: 'https://forno.celo.org',
|
|
||||||
[ChainId.MOONRIVER]: 'https://rpc.moonriver.moonbeam.network',
|
|
||||||
[ChainId.TELOS]: 'https://mainnet.telos.net/evm',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RPC
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { ChainId } from './chainIds'
|
|
||||||
|
|
||||||
import { InjectedConnector } from '@web3-react/injected-connector'
|
|
||||||
|
|
||||||
export const supportedChainIds = Object.values(ChainId) as number[]
|
|
||||||
|
|
||||||
export const injected = new InjectedConnector({
|
|
||||||
supportedChainIds,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const wallets = [
|
|
||||||
{
|
|
||||||
name: 'Injected',
|
|
||||||
connector: injected,
|
|
||||||
logo: 'https://cdn.iconscout.com/icon/free/png-256/metamask-2728406-2261817.png',
|
|
||||||
},
|
|
||||||
]
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { useEffect, useState, useRef } from 'react'
|
|
||||||
import Web3 from 'web3'
|
|
||||||
import { useWeb3React } from '@web3-react/core'
|
|
||||||
import RPC from '../config/rpc'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a web3 instance using the provider provided by useWallet
|
|
||||||
* with a fallback of an httpProver
|
|
||||||
* Recreate web3 instance only if the provider change
|
|
||||||
*/
|
|
||||||
const useWeb3 = () => {
|
|
||||||
const { library, chainId = 1 } = useWeb3React()
|
|
||||||
const refEth = useRef(library)
|
|
||||||
|
|
||||||
const [web3, setweb3] = useState(
|
|
||||||
library
|
|
||||||
? new Web3(library)
|
|
||||||
: // @ts-ignore TYPE NEEDS FIXING
|
|
||||||
new Web3(RPC[chainId])
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (library !== refEth.current) {
|
|
||||||
setweb3(
|
|
||||||
library
|
|
||||||
? new Web3(library)
|
|
||||||
: // @ts-ignore TYPE NEEDS FIXING
|
|
||||||
new Web3(RPC[chainId])
|
|
||||||
)
|
|
||||||
refEth.current = library
|
|
||||||
}
|
|
||||||
}, [library, setweb3, chainId])
|
|
||||||
|
|
||||||
return { web3, setweb3 }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useWeb3
|
|
5
examples/evm-multichain-dapp/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,15 +0,0 @@
|
||||||
/** @type {import('next').NextConfig} */
|
|
||||||
const nextConfig = {
|
|
||||||
images: {
|
|
||||||
remotePatterns: [
|
|
||||||
{
|
|
||||||
protocol: 'https',
|
|
||||||
hostname: 'raw.githubusercontent.com',
|
|
||||||
port: '',
|
|
||||||
pathname: '/my-account/**',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = nextConfig
|
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next dev",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@web3-react/abstract-connector": "^6.0.7",
|
|
||||||
"@web3-react/core": "^6.1.9",
|
|
||||||
"@web3-react/injected-connector": "^6.0.7",
|
|
||||||
"@web3-react/walletconnect-connector": "^6.2.13",
|
|
||||||
"bignumber.js": "^9.0.2",
|
|
||||||
"next": "latest",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"web3": "^1.7.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^18.6.2",
|
|
||||||
"@types/react": "^18.0.15",
|
|
||||||
"@types/react-dom": "^18.0.6",
|
|
||||||
"typescript": "^4.7.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import '../styles/globals.css'
|
|
||||||
import type { AppProps } from 'next/app'
|
|
||||||
import { Web3ReactProvider } from '@web3-react/core'
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
|
||||||
const getLibrary = (provider: any) => {
|
|
||||||
return provider
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Web3ReactProvider getLibrary={getLibrary}>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</Web3ReactProvider>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyApp
|
|
|
@ -1,183 +0,0 @@
|
||||||
import { useWeb3React } from '@web3-react/core'
|
|
||||||
import type { NextPage } from 'next'
|
|
||||||
import Head from 'next/head'
|
|
||||||
import Image from 'next/image'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import blockchains from '../config/blockchains.json'
|
|
||||||
import { ChainId } from '../config/chainIds'
|
|
||||||
import { NETWORK_ICON, NETWORK_LABEL } from '../config/networks'
|
|
||||||
import { injected, supportedChainIds, wallets } from '../config/wallets'
|
|
||||||
import useWeb3 from '../hooks/useWeb3'
|
|
||||||
|
|
||||||
import styles from '../styles/Home.module.css'
|
|
||||||
|
|
||||||
const Home: NextPage = () => {
|
|
||||||
const { account, activate, chainId, deactivate } = useWeb3React()
|
|
||||||
const [nativeBalance, setNativeBalance] = useState(0)
|
|
||||||
const [sendAddress, setSendAddress] = useState('')
|
|
||||||
const [sendAmount, setSendAmount] = useState('0')
|
|
||||||
|
|
||||||
const { web3 } = useWeb3()
|
|
||||||
// @ts-ignore TYPE NEEDS FIXING
|
|
||||||
const chainData = blockchains[chainId]
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// @ts-ignore TYPE NEEDS FIXING
|
|
||||||
if (window?.ethereum) {
|
|
||||||
activate(injected)
|
|
||||||
} else {
|
|
||||||
alert('You need to install a crypto wallet to run this Dapp!!')
|
|
||||||
}
|
|
||||||
}, [activate])
|
|
||||||
const fetchBalanceData = async () => {
|
|
||||||
const eth = await web3.eth.getBalance(account as string)
|
|
||||||
if (Number(eth) > 0) {
|
|
||||||
const bal = web3.utils.fromWei(eth, 'ether')
|
|
||||||
console.log({ eth, bal })
|
|
||||||
setNativeBalance(Number(bal))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
if (account) {
|
|
||||||
fetchBalanceData()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const sendEth = async () => {
|
|
||||||
const isValidAddress = web3.utils.isAddress(sendAddress)
|
|
||||||
if (isValidAddress && Number(sendAmount) > 0 && account) {
|
|
||||||
const tx = await web3.eth.sendTransaction({
|
|
||||||
from: account,
|
|
||||||
to: sendAddress,
|
|
||||||
// @ts-ignore TYPE NEEDS FIXING
|
|
||||||
|
|
||||||
value: web3.utils.toWei(sendAmount, 'ether'),
|
|
||||||
})
|
|
||||||
if (tx.transactionHash) {
|
|
||||||
alert(`Transaction Success!! ${tx.transactionHash}`)
|
|
||||||
fetchBalanceData()
|
|
||||||
}
|
|
||||||
console.log({ tx })
|
|
||||||
} else {
|
|
||||||
alert('Invalid Transaction Data')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={styles.container}>
|
|
||||||
<Head>
|
|
||||||
<title>Create Next App</title>
|
|
||||||
<meta name="description" content="Generated by create next app" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
{account ? (
|
|
||||||
<>
|
|
||||||
<div className="card">
|
|
||||||
<h4>
|
|
||||||
Connected to Network : {NETWORK_LABEL[chainId as ChainId]}
|
|
||||||
</h4>
|
|
||||||
<h4>
|
|
||||||
Native Balance : {nativeBalance || 0}{' '}
|
|
||||||
{chainData?.nativeCurrency?.symbol}
|
|
||||||
</h4>
|
|
||||||
<p>Account : {account}</p>
|
|
||||||
<button className="btn" onClick={() => deactivate()}>
|
|
||||||
Logout
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="card">
|
|
||||||
<h2>Send {chainData?.nativeCurrency?.symbol}</h2>
|
|
||||||
<div className="my-1">
|
|
||||||
<label htmlFor="sendAddress">Recipient Address</label>
|
|
||||||
<input
|
|
||||||
id="sendAddress"
|
|
||||||
className="mx-1"
|
|
||||||
type="text"
|
|
||||||
value={sendAddress}
|
|
||||||
onChange={(e) => setSendAddress(e?.target?.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="my-1">
|
|
||||||
<label htmlFor="sendAmount">Recipient Amount</label>
|
|
||||||
|
|
||||||
<input
|
|
||||||
id="sendAmount"
|
|
||||||
className="mx-1"
|
|
||||||
type="number"
|
|
||||||
value={sendAmount}
|
|
||||||
onChange={(e) => setSendAmount(e?.target?.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<h4>
|
|
||||||
Native Balance : {nativeBalance || 0}{' '}
|
|
||||||
{chainData?.nativeCurrency?.symbol}
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<button className="btn" onClick={sendEth}>
|
|
||||||
Send {chainData?.nativeCurrency?.symbol}{' '}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className="card">
|
|
||||||
<h1>Connect Wallet</h1>
|
|
||||||
{wallets?.map((wallet, idx) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={wallet?.name}
|
|
||||||
className="btn"
|
|
||||||
onClick={() => activate(wallet?.connector)}
|
|
||||||
>
|
|
||||||
{wallet?.name}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="card">
|
|
||||||
<h1>Supported Blockchains</h1>
|
|
||||||
<div className="flex flex-wrap">
|
|
||||||
{supportedChainIds?.map((chain, idx) =>
|
|
||||||
// @ts-ignore TYPE NEEDS FIXING
|
|
||||||
Number(chain) && NETWORK_ICON[Number(chain)] ? (
|
|
||||||
<div
|
|
||||||
key={Number(chain)}
|
|
||||||
className="flex items-center rounded-md"
|
|
||||||
style={{
|
|
||||||
background: 'black',
|
|
||||||
padding: '0.1em 0.25em',
|
|
||||||
margin: '1em 0.5em',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
// @ts-ignore TYPE NEEDS FIXING
|
|
||||||
|
|
||||||
src={NETWORK_ICON[Number(chain)]}
|
|
||||||
width={30}
|
|
||||||
height={30}
|
|
||||||
alt=""
|
|
||||||
className="rounded-md"
|
|
||||||
/>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
marginLeft: '0.5em',
|
|
||||||
fontSize: '12px',
|
|
||||||
padding: '0em 0.5em',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* @ts-ignore TYPE NEEDS FIXING */}
|
|
||||||
{NETWORK_LABEL[Number(chain)]}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
)}
|
|
||||||
<p>Note : The chains are extendable to any EVM based Blockchain.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Home
|
|
Before Width: | Height: | Size: 25 KiB |
|
@ -1,4 +0,0 @@
|
||||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,129 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
.card,
|
|
||||||
.footer {
|
|
||||||
border-color: #222;
|
|
||||||
}
|
|
||||||
.code {
|
|
||||||
background: #111;
|
|
||||||
}
|
|
||||||
.logo img {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
html {
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
color: white;
|
|
||||||
background: rgb(10, 10, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin: 5% 0%;
|
|
||||||
padding: 2%;
|
|
||||||
background: rgb(0, 0, 0);
|
|
||||||
background: -moz-radial-gradient(
|
|
||||||
circle,
|
|
||||||
rgba(0, 0, 0, 1) 0%,
|
|
||||||
rgba(11, 11, 78, 1) 35%,
|
|
||||||
rgba(0, 0, 0, 1) 100%
|
|
||||||
);
|
|
||||||
background: -webkit-radial-gradient(
|
|
||||||
circle,
|
|
||||||
rgba(0, 0, 0, 1) 0%,
|
|
||||||
rgba(11, 11, 78, 1) 35%,
|
|
||||||
rgba(0, 0, 0, 1) 100%
|
|
||||||
);
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
rgba(0, 0, 0, 1) 0%,
|
|
||||||
rgba(11, 11, 78, 1) 35%,
|
|
||||||
rgba(0, 0, 0, 1) 100%
|
|
||||||
);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#000000",endColorstr="#000000",GradientType=1);
|
|
||||||
border: 1px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.flex-wrap {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.my-1 {
|
|
||||||
margin-top: 1%;
|
|
||||||
margin-bottom: 1%;
|
|
||||||
}
|
|
||||||
.mx-1 {
|
|
||||||
margin-left: 1%;
|
|
||||||
margin-right: 1%;
|
|
||||||
}
|
|
||||||
.btn {
|
|
||||||
background-color: rgb(46, 46, 244);
|
|
||||||
padding: 0.5em 1em;
|
|
||||||
border: none;
|
|
||||||
border-radius: 2px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.btn:hover {
|
|
||||||
background-color: rgb(87, 87, 240);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.btn:active {
|
|
||||||
background-color: rgb(0, 0, 255);
|
|
||||||
}
|
|
||||||
.items-center {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.rounded {
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
.rounded-md {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"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"]
|
|
||||||
}
|
|
36
examples/fast-refresh-demo/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Fast Refresh Demo
|
|
||||||
|
|
||||||
Next.js ships with [Fast Refresh](https://nextjs.org/docs/basic-features/fast-refresh) which gives you instantaneous feedback on edits made to your React components.
|
|
||||||
|
|
||||||
This demos shows how the state of an auto incrementing value and a classic counter is preserved after edits or if there are errors.
|
|
||||||
|
|
||||||
## 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/fast-refresh-demo)
|
|
||||||
|
|
||||||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/fast-refresh-demo&project-name=fast-refresh-demo&repository-name=fast-refresh-demo)
|
|
||||||
|
|
||||||
## 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 fast-refresh-demo fast-refresh-demo-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example fast-refresh-demo fast-refresh-demo-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example fast-refresh-demo fast-refresh-demo-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)).
|
|
|
@ -1,32 +0,0 @@
|
||||||
button.btn {
|
|
||||||
margin: 0;
|
|
||||||
border: 1px solid #d1d1d1;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 0.5em;
|
|
||||||
vertical-align: middle;
|
|
||||||
white-space: normal;
|
|
||||||
background: none;
|
|
||||||
line-height: 1;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-family: inherit;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn {
|
|
||||||
padding: 0.65em 1em;
|
|
||||||
background: #0076ff;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
button.btn:focus {
|
|
||||||
outline: 0;
|
|
||||||
border-color: #0076ff;
|
|
||||||
}
|
|
||||||
button.btn:hover {
|
|
||||||
background: rgba(0, 118, 255, 0.8);
|
|
||||||
}
|
|
||||||
button.btn:focus {
|
|
||||||
box-shadow: 0 0 0 2px rgba(0, 118, 255, 0.5);
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import styles from './Button.module.css'
|
|
||||||
|
|
||||||
type ButtonProps = {
|
|
||||||
onClick: React.MouseEventHandler
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Button({ children, ...props }: ButtonProps) {
|
|
||||||
return (
|
|
||||||
<button type="button" className={styles.btn} {...props}>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { useCallback, useState } from 'react'
|
|
||||||
import Button from './Button'
|
|
||||||
|
|
||||||
export default function ClickCount() {
|
|
||||||
const [count, setCount] = useState(0)
|
|
||||||
const increment = useCallback(() => {
|
|
||||||
setCount((v) => v + 1)
|
|
||||||
}, [setCount])
|
|
||||||
|
|
||||||
return <Button onClick={increment}>Clicks: {count}</Button>
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica',
|
|
||||||
'Arial', sans-serif;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.65;
|
|
||||||
word-break: break-word;
|
|
||||||
font-kerning: auto;
|
|
||||||
font-variant: normal;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
hyphens: auto;
|
|
||||||
}
|
|
5
examples/fast-refresh-demo/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"next": "latest",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^18.11.5",
|
|
||||||
"@types/react": "^18.0.23",
|
|
||||||
"@types/react-dom": "^18.0.7",
|
|
||||||
"typescript": "^4.8.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { AppProps } from 'next/app'
|
|
||||||
import '../global.css'
|
|
||||||
|
|
||||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
|
||||||
return <Component {...pageProps} />
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
|
||||||
import Button from '../components/Button'
|
|
||||||
import ClickCount from '../components/ClickCount'
|
|
||||||
import styles from '../styles/home.module.css'
|
|
||||||
|
|
||||||
function throwError() {
|
|
||||||
console.log(
|
|
||||||
// The function body() is not defined
|
|
||||||
// @ts-ignore
|
|
||||||
document.body()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
const [count, setCount] = useState(0)
|
|
||||||
const increment = useCallback(() => {
|
|
||||||
setCount((v) => v + 1)
|
|
||||||
}, [setCount])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const r = setInterval(() => {
|
|
||||||
increment()
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(r)
|
|
||||||
}
|
|
||||||
}, [increment])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main className={styles.main}>
|
|
||||||
<h1>Fast Refresh Demo</h1>
|
|
||||||
<p>
|
|
||||||
Fast Refresh is a Next.js feature that gives you instantaneous feedback
|
|
||||||
on edits made to your React components, without ever losing component
|
|
||||||
state.
|
|
||||||
</p>
|
|
||||||
<hr className={styles.hr} />
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
Auto incrementing value. The counter won't reset after edits or if
|
|
||||||
there are errors.
|
|
||||||
</p>
|
|
||||||
<p>Current value: {count}</p>
|
|
||||||
</div>
|
|
||||||
<hr className={styles.hr} />
|
|
||||||
<div>
|
|
||||||
<p>Component with state.</p>
|
|
||||||
<ClickCount />
|
|
||||||
</div>
|
|
||||||
<hr className={styles.hr} />
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
The button below will throw 2 errors. You'll see the error overlay to
|
|
||||||
let you know about the errors but it won't break the page or reset
|
|
||||||
your state.
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
onClick={(e) => {
|
|
||||||
setTimeout(() => document.parentNode, 0)
|
|
||||||
throwError()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Throw an Error
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<hr className={styles.hr} />
|
|
||||||
</main>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
.main {
|
|
||||||
padding: 20px 20px 60px;
|
|
||||||
max-width: 680px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hr {
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid #efefef;
|
|
||||||
margin: 3em auto;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"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"]
|
|
||||||
}
|
|
36
examples/hello-world-esm/.gitignore
vendored
|
@ -1,36 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
.yarn/install-state.gz
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env*.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
|
@ -1,27 +0,0 @@
|
||||||
# ESM Hello World example
|
|
||||||
|
|
||||||
This example shows the most basic idea behind Next.js, and it's running on native [esm](https://nodejs.org/api/esm.html) mode. We have 2 pages: `pages/index.tsx` and `pages/about.tsx`. The former responds to `/` requests and the latter to `/about`. Using `next/link` you can add hyperlinks between them with universal routing capabilities. The `day` directory shows that you can have subdirectories.
|
|
||||||
|
|
||||||
## Deploy your own
|
|
||||||
|
|
||||||
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example-esm) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/hello-world-esm)
|
|
||||||
|
|
||||||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/hello-world-esm&project-name=hello-world-esm&repository-name=hello-world-esm)
|
|
||||||
|
|
||||||
## 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 hello-world-esm hello-world-esm-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn create next-app --example hello-world-esm hello-world-esm-app
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm create next-app --example hello-world-esm hello-world-esm-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)).
|
|
5
examples/hello-world-esm/next-env.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
/// <reference types="next" />
|
|
||||||
/// <reference types="next/image-types/global" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"next": "latest",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^18.11.5",
|
|
||||||
"@types/react": "^18.0.23",
|
|
||||||
"@types/react-dom": "^18.0.7",
|
|
||||||
"typescript": "^4.8.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function AboutPage() {
|
|
||||||
return <div>About us</div>
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function DayPage() {
|
|
||||||
return <div>Hello Day</div>
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
export default function IndexPage() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Hello World. <Link href="/about">About</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|