diff --git a/examples/browser-nextjs/.eslintrc b/examples/browser-nextjs/.eslintrc new file mode 100644 index 00000000..80a478c4 --- /dev/null +++ b/examples/browser-nextjs/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": ["next", "next/core-web-vitals"], + "root": true +} diff --git a/examples/browser-nextjs/.gitignore b/examples/browser-nextjs/.gitignore new file mode 100644 index 00000000..1437c53f --- /dev/null +++ b/examples/browser-nextjs/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/browser-nextjs/README.md b/examples/browser-nextjs/README.md new file mode 100644 index 00000000..dc8cdd61 --- /dev/null +++ b/examples/browser-nextjs/README.md @@ -0,0 +1,146 @@ +

+ + IPFS in JavaScript logo + +

+ +

IPFS Next App

+ +

+ Using js-ipfs in a `create-next-app` +
+
+ +
+ Explore the docs + · + View Demo + · + Report Bug + · + Request Feature +

+ +## Table of Contents + +- [Table of Contents](#table-of-contents) +- [About The Project](#about-the-project) +- [Getting Started](#getting-started) + - [Pre requisites](#pre-requisites) + - [Installation and Running example](#installation-and-running-example) + - [Available Scripts](#available-scripts) + - [`npm start`](#npm-start) + - [`npm run build`](#npm-run-build) +- [Usage](#usage) + - [Learn More](#learn-more) + - [Deploy on Vercel](#deploy-on-vercel) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Want to hack on IPFS?](#want-to-hack-on-ipfs) + +## About The Project + +- Read the [docs](https://github.com/ipfs/js-ipfs/tree/master/docs) +- Look into other [examples](https://github.com/ipfs/js-ipfs/tree/master/examples) to learn how to spawn an IPFS node in Node.js and in the Browser +- Consult the [Core API docs](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api) to see what you can do with an IPFS node +- Visit https://dweb-primer.ipfs.io to learn about IPFS and the concepts that underpin it +- Head over to https://proto.school to take interactive tutorials that cover core IPFS APIs +- Check out https://docs.ipfs.io for tips, how-tos and more +- See https://blog.ipfs.io for news and more +- Need help? Please ask 'How do I?' questions on https://discuss.ipfs.io + +## Getting Started + +### Pre requisites + +Make sure you have installed all of the following prerequisites on your development machine: + +- Git - [Download & Install Git](https://git-scm.com/downloads). OSX and Linux machines typically have this already installed. +- Node.js - [Download & Install Node.js](https://nodejs.org/en/download/) and the npm package manager. + +### Installation and Running example + +```console +> npm install +> npm start +``` + +Now open your browser at `http://localhost:3000` + +### Available Scripts + +In the project directory, you can run: + +#### `npm start` + +Runs the app in the development mode.
+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 any lint errors in the console. + +#### `npm run build` + +Builds the app for production to the `dist` folder.
+It correctly bundles in production mode and optimizes the build for the best performance. + +## Usage + +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) integrated with `js-ipfs`. + +You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +### Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +### Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +_For more examples, please refer to the [Documentation](#documentation)_ + +## Documentation + +- [Config](https://docs.ipfs.io/) +- [Core API](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api) +- [Examples](https://github.com/ipfs/js-ipfs/tree/master/examples) +- [Development](https://github.com/ipfs/js-ipfs/blob/master/docs/DEVELOPMENT.md) + +## Contributing + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +1. Fork the IPFS Project +2. Create your Feature Branch (`git checkout -b feature/amazing-feature`) +3. Commit your Changes (`git commit -a -m 'feat: add some amazing feature'`) +4. Push to the Branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) + +The IPFS implementation in JavaScript needs your help! There are a few things you can do right now to help out: + +Read the [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md) and [JavaScript Contributing Guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING_JS.md). + +- **Check out existing issues** The [issue list](https://github.com/ipfs/js-ipfs/issues) has many that are marked as ['help wanted'](https://github.com/ipfs/js-ipfs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22) or ['difficulty:easy'](https://github.com/ipfs/js-ipfs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Adifficulty%3Aeasy) which make great starting points for development, many of which can be tackled with no prior IPFS knowledge +- **Look at the [IPFS Roadmap](https://github.com/ipfs/roadmap)** This are the high priority items being worked on right now +- **Perform code reviews** More eyes will help + a. speed the project along + b. ensure quality, and + c. reduce possible future bugs. +- **Add tests**. There can never be enough tests. +- **Join the [Weekly Core Implementations Call](https://github.com/ipfs/team-mgmt/issues/992)** it's where everyone discusses what's going on with IPFS and what's next diff --git a/examples/browser-nextjs/components/ipfs.js b/examples/browser-nextjs/components/ipfs.js new file mode 100644 index 00000000..f6e86f98 --- /dev/null +++ b/examples/browser-nextjs/components/ipfs.js @@ -0,0 +1,42 @@ +import { useState, useEffect } from 'react' +import Ipfs from 'ipfs' + +const IpfsComponent = () => { + const [id, setId] = useState(null); + const [ipfs, setIpfs] = useState(null); + const [version, setVersion] = useState(null); + const [isOnline, setIsOnline] = useState(false); + + useEffect(() => { + const init = async () => { + if (ipfs) return + + const node = await Ipfs.create(); + + const nodeId = await node.id(); + const nodeVersion = await node.version(); + const nodeIsOnline = node.isOnline; + + setIpfs(node); + setId(nodeId.id); + setVersion(nodeVersion.version); + setIsOnline(nodeIsOnline); + } + + init() + }, [ipfs]); + + if (!ipfs) { + return

Connecting to IPFS...

+ } + + return ( +
+

ID: {id}

+

Version: {version}

+

Status: {isOnline ? 'Online' : 'Offline'}

+
+ ) +} + +export default IpfsComponent diff --git a/examples/browser-nextjs/next.config.js b/examples/browser-nextjs/next.config.js new file mode 100644 index 00000000..c9432fb6 --- /dev/null +++ b/examples/browser-nextjs/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + reactStrictMode: true, + // https://github.com/vercel/next.js/issues/21079 + // Remove the workaround the issue is fixed + images: { + loader: "imgix", + path: "", + }, +} diff --git a/examples/browser-nextjs/package.json b/examples/browser-nextjs/package.json new file mode 100644 index 00000000..5cb593b7 --- /dev/null +++ b/examples/browser-nextjs/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-browser-nextjs", + "version": "1.0.0", + "private": true, + "scripts": { + "clean": "rimraf ./dist ./.next", + "dev": "next dev", + "build": "next build && next export -o dist", + "serve": "npm run dev", + "start": "next start", + "lint": "next lint", + "test:example": "npm run build && playwright test tests" + }, + "dependencies": { + "ipfs": "^0.55.4", + "next": "11.0.1", + "react": "17.0.2", + "react-dom": "17.0.2" + }, + "devDependencies": { + "eslint": "7.30.0", + "eslint-config-next": "11.0.1", + "test-util-ipfs-example": "^1.0.0", + "rimraf": "^3.0.2" + } +} diff --git a/examples/browser-nextjs/pages/_app.js b/examples/browser-nextjs/pages/_app.js new file mode 100644 index 00000000..1e1cec92 --- /dev/null +++ b/examples/browser-nextjs/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/globals.css' + +function MyApp({ Component, pageProps }) { + return +} + +export default MyApp diff --git a/examples/browser-nextjs/pages/api/hello.js b/examples/browser-nextjs/pages/api/hello.js new file mode 100644 index 00000000..df63de88 --- /dev/null +++ b/examples/browser-nextjs/pages/api/hello.js @@ -0,0 +1,5 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction + +export default function handler(req, res) { + res.status(200).json({ name: 'John Doe' }) +} diff --git a/examples/browser-nextjs/pages/index.js b/examples/browser-nextjs/pages/index.js new file mode 100644 index 00000000..0f24cf8e --- /dev/null +++ b/examples/browser-nextjs/pages/index.js @@ -0,0 +1,93 @@ +import Head from 'next/head' +import Image from 'next/image' +import styles from '../styles/Home.module.css' + +import IpfsComponent from '../components/ipfs' + +export default function Home() { + return ( +
+ + Create Next App + + + + +
+

+ Welcome to Next.js! +

+ +

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

+ +
+ +

Documentation →

+

Find in-depth information about Next.js features and API.

+
+ + +

Learn →

+

Learn about Next.js in an interactive course with quizzes!

+
+ + +

Examples →

+

Discover and deploy boilerplate example Next.js projects.

+
+ + +

Deploy →

+

+ Instantly deploy your Next.js site to a public URL with Vercel. +

+
+ + +

IPFS Documentation →

+

+ Learn how to build the future of the internet +

+
+ + +

IPFS Tutorials →

+

+ Interactive tutorials on decentralized web protocols +

+
+
+ + +
+ + +
+ ) +} diff --git a/examples/browser-nextjs/public/favicon.ico b/examples/browser-nextjs/public/favicon.ico new file mode 100644 index 00000000..b2f1f968 Binary files /dev/null and b/examples/browser-nextjs/public/favicon.ico differ diff --git a/examples/browser-nextjs/public/vercel.svg b/examples/browser-nextjs/public/vercel.svg new file mode 100644 index 00000000..fbf0e25a --- /dev/null +++ b/examples/browser-nextjs/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/browser-nextjs/styles/Home.module.css b/examples/browser-nextjs/styles/Home.module.css new file mode 100644 index 00000000..35454bb7 --- /dev/null +++ b/examples/browser-nextjs/styles/Home.module.css @@ -0,0 +1,121 @@ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; +} + +.main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + 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 { + 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; + margin-top: 3rem; +} + +.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; + width: 45%; +} + +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} + +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} + +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} + +.logo { + height: 1em; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/examples/browser-nextjs/styles/globals.css b/examples/browser-nextjs/styles/globals.css new file mode 100644 index 00000000..e5e2dcc2 --- /dev/null +++ b/examples/browser-nextjs/styles/globals.css @@ -0,0 +1,16 @@ +html, +body { + padding: 0; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +* { + box-sizing: border-box; +} diff --git a/examples/browser-nextjs/tests/test.js b/examples/browser-nextjs/tests/test.js new file mode 100644 index 00000000..38a7ac4a --- /dev/null +++ b/examples/browser-nextjs/tests/test.js @@ -0,0 +1,28 @@ +'use strict' + +const { test, expect } = require('@playwright/test'); +const { playwright } = require('test-util-ipfs-example'); + +// Setup +const play = test.extend({ + ...playwright.servers(), +}); + +play.describe('integrate ipfs with nextjs:', () => { + // DOM + const id = "[data-test=id]" + const version = "[data-test=version]" + const status = "[data-test=status]" + + play.beforeEach(async ({servers, page}) => { + await page.goto(`http://localhost:${servers[0].port}/`); + }) + + play('should properly initialized a IPFS node and print some properties', async ({ page }) => { + await page.waitForSelector(id) + + expect(await page.isVisible(id)).toBeTruthy(); + expect(await page.isVisible(version)).toBeTruthy(); + expect(await page.textContent(status)).toContain('Online'); + }); +});