examples: cleanup (#57845)

Remove examples that were linking to just READMEs, or outdated / discontinued ones.
This commit is contained in:
Lee Robinson 2023-10-31 19:08:55 -05:00 committed by GitHub
parent 75958bbc46
commit ac54377e67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
664 changed files with 50 additions and 20023 deletions

View file

@ -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

View file

@ -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)).

View file

@ -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
}
}

View file

@ -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

View file

@ -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" />
}

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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"
}
}

View file

@ -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 &rarr;</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 &rarr;</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 &rarr;</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=&#123;`&#123;&#123;imageUrl&#125;&#125;`&#125;</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

View file

@ -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

View file

@ -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>

View file

@ -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"
}

View file

@ -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: [],
},
})

View file

@ -1,4 +0,0 @@
const btn = document.querySelector('button')
btn.addEventListener('click', () => {
document.body.textContent = 'Hello World!'
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -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"]
}

View file

@ -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

View file

@ -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)).

View file

@ -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
// }
// }

View file

@ -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.

View file

@ -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"
}
}

View file

@ -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

View file

@ -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"]
}

View file

@ -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

View file

@ -1,3 +0,0 @@
AUTHSIGNAL_SECRET=
SESSION_TOKEN_SECRET=
REDIRECT_URL=http://localhost:3000/api/finalize-login

View file

@ -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

View file

@ -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/).

View file

@ -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;
}

View file

@ -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>
</>
)
}

View file

@ -1,3 +0,0 @@
export * from './dashboard'
export * from './layout'
export * from './login'

View file

@ -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}
</>
)

View file

@ -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;
}

View file

@ -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>
)

View file

@ -1,5 +0,0 @@
import { Authsignal } from '@authsignal/node'
const secret = process.env.AUTHSIGNAL_SECRET!
export const authsignal = new Authsignal({ secret })

View file

@ -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
}

View file

@ -1,2 +0,0 @@
export * from './authsignal'
export * from './cookies'

View file

@ -1,6 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig

View file

@ -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"
}
}

View file

@ -1,6 +0,0 @@
import type { AppProps } from 'next/app'
import './globals.css'
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

View file

@ -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('/')
}

View file

@ -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)
}

View file

@ -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 })
}

View file

@ -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%;
}

View file

@ -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>
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -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

View file

@ -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"]
}

View file

@ -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

View file

@ -1,3 +0,0 @@
## Deprecated
The main [blog-starter](/examples/blog-starter) example has been refactored to use TypeScript, so this example is deprecated.

View file

@ -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

View file

@ -1,3 +0,0 @@
## Deprecated
The main [custom-server](/examples/custom-server) example has been refactored to use TypeScript, so this example is deprecated.

View file

@ -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

View file

@ -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)).

View file

@ -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.

View file

@ -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"
}
}

View file

@ -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>
</>
)
}

View file

@ -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>
</>
)
}

View file

@ -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"]
}

View file

@ -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>

View file

@ -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

View file

@ -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)).

View file

@ -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"
}
]

View file

@ -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"
}
}

View file

@ -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,
}

View file

@ -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',
}

View file

@ -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

View file

@ -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',
},
]

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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"
}
}

View file

@ -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

View file

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -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

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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"]
}

View file

@ -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

View file

@ -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)).

View file

@ -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);
}

View file

@ -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>
)
}

View file

@ -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>
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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"
}
}

View file

@ -1,6 +0,0 @@
import { AppProps } from 'next/app'
import '../global.css'
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

View file

@ -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>
)
}

View file

@ -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;
}

View file

@ -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"]
}

View file

@ -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

View file

@ -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)).

View file

@ -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.

View file

@ -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"
}
}

View file

@ -1,3 +0,0 @@
export default function AboutPage() {
return <div>About us</div>
}

View file

@ -1,3 +0,0 @@
export default function DayPage() {
return <div>Hello Day</div>
}

View file

@ -1,9 +0,0 @@
import Link from 'next/link'
export default function IndexPage() {
return (
<div>
Hello World. <Link href="/about">About</Link>
</div>
)
}

Some files were not shown because too many files have changed in this diff Show more