diff --git a/.github/ISSUE_TEMPLATE/1.Bug_report.md b/.github/ISSUE_TEMPLATE/1.Bug_report.md index 0deaa884aae96..3204d20475f45 100644 --- a/.github/ISSUE_TEMPLATE/1.Bug_report.md +++ b/.github/ISSUE_TEMPLATE/1.Bug_report.md @@ -1,38 +1,38 @@ ---- -name: Bug report -about: Create a bug report for the Next.js core / examples ---- - -# Bug report - -## Describe the bug - -A clear and concise description of what the bug is. - -## To Reproduce - -Steps to reproduce the behavior, please provide code snippets or a repository: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -## Expected behavior - -A clear and concise description of what you expected to happen. - -## Screenshots - -If applicable, add screenshots to help explain your problem. - -## System information - -- OS: [e.g. macOS, Windows] -- Browser (if applies) [e.g. chrome, safari] -- Version of Next.js: [e.g. 6.0.2] -- Version of Node.js: [e.g. 10.10.0] - -## Additional context - -Add any other context about the problem here. +--- +name: Bug report +about: Create a bug report for the Next.js core / examples +--- + +# Bug report + +## Describe the bug + +A clear and concise description of what the bug is. + +## To Reproduce + +Steps to reproduce the behavior, please provide code snippets or a repository: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +## Expected behavior + +A clear and concise description of what you expected to happen. + +## Screenshots + +If applicable, add screenshots to help explain your problem. + +## System information + +- OS: [e.g. macOS, Windows] +- Browser (if applies) [e.g. chrome, safari] +- Version of Next.js: [e.g. 6.0.2] +- Version of Node.js: [e.g. 10.10.0] + +## Additional context + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/2.Feature_request.md b/.github/ISSUE_TEMPLATE/2.Feature_request.md index 92a257d1a7e80..c3cfe03750198 100644 --- a/.github/ISSUE_TEMPLATE/2.Feature_request.md +++ b/.github/ISSUE_TEMPLATE/2.Feature_request.md @@ -1,22 +1,22 @@ ---- -name: Feature request -about: Create a feature request for the Next.js core ---- - -# Feature request - -## Is your feature request related to a problem? Please describe. - -A clear and concise description of what you want and what your use case is. - -## Describe the solution you'd like - -A clear and concise description of what you want to happen. - -## Describe alternatives you've considered - -A clear and concise description of any alternative solutions or features you've considered. - -## Additional context - -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Create a feature request for the Next.js core +--- + +# Feature request + +## Is your feature request related to a problem? Please describe. + +A clear and concise description of what you want and what your use case is. + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context + +Add any other context or screenshots about the feature request here. diff --git a/examples/with-next-less/README.md b/examples/with-next-less/README.md index ced34fb230dae..b01c9249b3177 100644 --- a/examples/with-next-less/README.md +++ b/examples/with-next-less/README.md @@ -1,44 +1,44 @@ -# Example App with next-less - -This example demonstrates how to use the [next-less plugin](https://github.com/zeit/next-plugins/tree/master/packages/next-less). - -It includes patterns for with and without CSS Modules, with PostCSS and with additional webpack configurations on top of the next-less plugin. - -## Deploy your own - -Deploy the example using [Vercel](https://vercel.com): - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-next-less) - -## How to use - -### Using `create-next-app` - -Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: - -```bash -npm init next-app --example with-next-less with-next-less-app -# or -yarn create next-app --example with-next-less with-next-less-app -``` - -### Download manually - -Download the example: - -```bash -curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-next-less -cd with-next-less -``` - -Install it and run: - -```bash -npm install -npm run dev -# or -yarn -yarn dev -``` - -Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). +# Example App with next-less + +This example demonstrates how to use the [next-less plugin](https://github.com/zeit/next-plugins/tree/master/packages/next-less). + +It includes patterns for with and without CSS Modules, with PostCSS and with additional webpack configurations on top of the next-less plugin. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-next-less) + +## How to use + +### Using `create-next-app` + +Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npm init next-app --example with-next-less with-next-less-app +# or +yarn create next-app --example with-next-less with-next-less-app +``` + +### Download manually + +Download the example: + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-next-less +cd with-next-less +``` + +Install it and run: + +```bash +npm install +npm run dev +# or +yarn +yarn dev +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-next-less/next.config.js b/examples/with-next-less/next.config.js index da95eeab357cb..723f5c3891d60 100644 --- a/examples/with-next-less/next.config.js +++ b/examples/with-next-less/next.config.js @@ -1,17 +1,17 @@ -const withLess = require('@zeit/next-less') - -/* Without CSS Modules, with PostCSS */ -module.exports = withLess() - -/* With CSS Modules */ -// module.exports = withLess({ cssModules: true }) - -/* With additional configuration on top of CSS Modules */ -/* -module.exports = withLess({ - cssModules: true, - webpack: function (config) { - return config; - } -}); -*/ +const withLess = require('@zeit/next-less') + +/* Without CSS Modules, with PostCSS */ +module.exports = withLess() + +/* With CSS Modules */ +// module.exports = withLess({ cssModules: true }) + +/* With additional configuration on top of CSS Modules */ +/* +module.exports = withLess({ + cssModules: true, + webpack: function (config) { + return config; + } +}); +*/ diff --git a/examples/with-next-less/pages/_document.js b/examples/with-next-less/pages/_document.js index f0ba19e663ca9..ff2803c511f96 100644 --- a/examples/with-next-less/pages/_document.js +++ b/examples/with-next-less/pages/_document.js @@ -1,21 +1,21 @@ -/* -In production the stylesheet is compiled to .next/static/style.css and served from /_next/static/style.css - -You have to include it into the page using either next/head or a custom _document.js, as is being done in this file. -*/ - -import Document, { Head, Main, NextScript } from 'next/document' - -export default class MyDocument extends Document { - render() { - return ( - - - -
- - - - ) - } -} +/* +In production the stylesheet is compiled to .next/static/style.css and served from /_next/static/style.css + +You have to include it into the page using either next/head or a custom _document.js, as is being done in this file. +*/ + +import Document, { Head, Main, NextScript } from 'next/document' + +export default class MyDocument extends Document { + render() { + return ( + + + +
+ + + + ) + } +} diff --git a/examples/with-next-less/pages/index.js b/examples/with-next-less/pages/index.js index cdf852b7c1ab9..7e99813411954 100644 --- a/examples/with-next-less/pages/index.js +++ b/examples/with-next-less/pages/index.js @@ -1,9 +1,9 @@ -// Without CSS Modules -import '../style.less' -export default () =>
Hello Less!
- -// With CSS Modules -/* -import style from '../style.less' -export default () =>
Hello Less!
-*/ +// Without CSS Modules +import '../style.less' +export default () =>
Hello Less!
+ +// With CSS Modules +/* +import style from '../style.less' +export default () =>
Hello Less!
+*/ diff --git a/examples/with-userbase/.env.example b/examples/with-userbase/.env.example new file mode 100644 index 0000000000000..8df2e2be22992 --- /dev/null +++ b/examples/with-userbase/.env.example @@ -0,0 +1 @@ +USERBASE_APP_ID= \ No newline at end of file diff --git a/examples/with-userbase/.gitignore b/examples/with-userbase/.gitignore new file mode 100644 index 0000000000000..dfdfb85e33db7 --- /dev/null +++ b/examples/with-userbase/.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 + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.now \ No newline at end of file diff --git a/examples/with-userbase/README.md b/examples/with-userbase/README.md new file mode 100644 index 0000000000000..c84e780b579cc --- /dev/null +++ b/examples/with-userbase/README.md @@ -0,0 +1,96 @@ +# Userbase Example + +This is an example of using [Userbase](https://userbase.com) in a Next.js project. + +Deployed Demo: [https://next-userbase.now.sh](https://next-userbase.now.sh) + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-userbase) + +## How to use + +### Using `create-next-app` + +Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npm init next-app --example with-userbase next-userbase-app +# or +yarn create next-app --example with-userbase next-userbase-app +``` + +### Download manually + +Download the example: + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-userbase +cd with-userbase +``` + +Install it and run: + +```bash +npm install +npm run dev +# or +yarn +yarn dev +``` + +## Configuration + +### Step 1. Create an account on Userbase + +First, [create an account on Userbase](https://userbase.com). + +After creating an account, make note of your _App ID_ which you'll be needing later. + +### Step 2. Setting up environment variables + +Copy the `.env.example` file in this directory to `.env` (which will be ignored by Git): + +```bash +cp .env.example .env +``` + +Then set the variable on `.env`: + +- `USERBASE_APP_ID` should be the _App ID_ from when you created your Userbase account. + +Your `.env` file should look like this: + +```bash +USERBASE_APP_ID=... +``` + +### Step 3. Run Next.js in development mode + +```bash +npm install +npm run dev + +# or + +yarn install +yarn dev +``` + +Your todo app should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/zeit/next.js/discussions). + +### Step 4. Deploy on Vercel + +You can deploy this app to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). + +To deploy on Vercel, you need to set the environment variables with **Now Secrets** using [Now CLI](https://vercel.com/download) ([Documentation](https://vercel.com/docs/now-cli#commands/secrets)). + +Install [Now CLI](https://vercel.com/download), log in to your account from the CLI, and run the following commands to add the environment variables. Replace `` and `` with the corresponding strings in `.env`. + +``` +now secrets add userbase-app-id +``` + +Then push the project to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) to deploy. diff --git a/examples/with-userbase/components/layout/index.js b/examples/with-userbase/components/layout/index.js new file mode 100644 index 0000000000000..ea8222e6f0f3b --- /dev/null +++ b/examples/with-userbase/components/layout/index.js @@ -0,0 +1,11 @@ +import Nav from '../nav' +function Layout({ user, setUser, children }) { + return ( +
+
+ ) +} + +export default Layout diff --git a/examples/with-userbase/components/modal/index.js b/examples/with-userbase/components/modal/index.js new file mode 100644 index 0000000000000..d789ffc050bda --- /dev/null +++ b/examples/with-userbase/components/modal/index.js @@ -0,0 +1,114 @@ +import { useState, useEffect } from 'react' +import userbase from 'userbase-js' + +function LoginModal({ toggle, modalType, setUser }) { + const [username, setUsername] = useState('') + const [password, setPassword] = useState('') + const [loading, setLoading] = useState() + const [error, setError] = useState() + + useEffect(() => { + setError('') + }, [modalType]) + + async function handleSignUp(e) { + e.preventDefault() + setLoading(true) + try { + const user = await userbase.signUp({ + username, + password, + rememberMe: 'none', + }) + setUser(user) + setLoading(false) + toggle(false) + } catch (e) { + setLoading(false) + setError(e.message) + } + } + + async function handleLogIn(e) { + e.preventDefault() + setLoading(true) + try { + const user = await userbase.signIn({ + username, + password, + rememberMe: 'none', + }) + setUser(user) + setLoading(false) + toggle(false) + } catch (e) { + setLoading(false) + setError(e.message) + } + } + + return ( +
+
+ + setUsername(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ toggle(false)} + > + Cancel + + {modalType === 'logIn' ? ( + + ) : ( + + )} +
+

{error}

+
+ ) +} + +export default LoginModal diff --git a/examples/with-userbase/components/nav/index.js b/examples/with-userbase/components/nav/index.js new file mode 100644 index 0000000000000..659b2b8bfec57 --- /dev/null +++ b/examples/with-userbase/components/nav/index.js @@ -0,0 +1,65 @@ +import { useState } from 'react' +import LoginModal from '../modal' + +import userbase from 'userbase-js' + +export default function Nav({ user, setUser }) { + const [open, setOpen] = useState() + const [modalType, setModalType] = useState() + + function openModal(type) { + setOpen(true) + setModalType(type) + } + + async function logOut() { + try { + await userbase.signOut() + setUser(null) + } catch (e) { + console.error(e.message) + } + } + + return ( + + ) +} diff --git a/examples/with-userbase/components/todo-form/index.js b/examples/with-userbase/components/todo-form/index.js new file mode 100644 index 0000000000000..53f261445041e --- /dev/null +++ b/examples/with-userbase/components/todo-form/index.js @@ -0,0 +1,132 @@ +import { useState, useEffect } from 'react' +import userbase from 'userbase-js' + +function Todo({ name, done, toggleComplete, deleteTodo }) { + return ( +
  • +
    + {name} + + +
    +
  • + ) +} + +function TodoForm() { + const [newTodo, setNewTodo] = useState('') + const [todos, setTodos] = useState([]) + const [disabled, setDisabled] = useState() + + useEffect(() => { + async function openDatabase() { + try { + console.log('opening db...') + await userbase.openDatabase({ + databaseName: 'next-userbase-todos', + changeHandler: function(items) { + setTodos(items) + }, + }) + } catch (e) { + console.error(e.message) + } + } + openDatabase() + }, []) + + async function addTodo(e) { + e.preventDefault() + setDisabled(true) + try { + await userbase.insertItem({ + databaseName: 'next-userbase-todos', + item: { name: newTodo, done: false }, + }) + setNewTodo('') + setDisabled(false) + } catch (e) { + console.error(e.message) + setDisabled(false) + } + } + + async function toggleComplete(itemId, currentValue) { + try { + await userbase.updateItem({ + databaseName: 'next-userbase-todos', + item: { ...currentValue, done: !currentValue.done }, + itemId, + }) + } catch (e) { + console.error(e.message) + } + } + + function handleNewTodo(e) { + e.preventDefault() + setNewTodo(e.target.value) + } + + async function deleteTodo(itemId) { + setDisabled(true) + try { + await userbase.deleteItem({ + databaseName: 'next-userbase-todos', + itemId, + }) + setNewTodo('') + setDisabled(false) + } catch (e) { + console.error(e.message) + setDisabled(false) + } + } + + return ( +
    +
      + {todos.map(todo => ( + toggleComplete(todo.itemId, todo.item)} + deleteTodo={() => deleteTodo(todo.itemId)} + /> + ))} +
    +
    + + +
    +
    + ) +} + +export default TodoForm diff --git a/examples/with-userbase/next.config.js b/examples/with-userbase/next.config.js new file mode 100644 index 0000000000000..fb7383baa54e4 --- /dev/null +++ b/examples/with-userbase/next.config.js @@ -0,0 +1,7 @@ +require('dotenv').config() + +module.exports = { + env: { + USERBASE_APP_ID: process.env.USERBASE_APP_ID, + }, +} diff --git a/examples/with-userbase/now.json b/examples/with-userbase/now.json new file mode 100644 index 0000000000000..fd69c3e7cbbe5 --- /dev/null +++ b/examples/with-userbase/now.json @@ -0,0 +1,7 @@ +{ + "build": { + "env": { + "USERBASE_APP_ID": "@userbase-app-id" + } + } +} diff --git a/examples/with-userbase/package.json b/examples/with-userbase/package.json new file mode 100644 index 0000000000000..2bbe1a76b20b8 --- /dev/null +++ b/examples/with-userbase/package.json @@ -0,0 +1,21 @@ +{ + "name": "with-tailwindcss", + "version": "1.0.0", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "dotenv": "8.2.0", + "next": "^9.2.0", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "userbase-js": "^1.3.0" + }, + "devDependencies": { + "@fullhuman/postcss-purgecss": "^1.3.0", + "postcss-preset-env": "^6.7.0", + "tailwindcss": "^1.1.4" + } +} diff --git a/examples/with-userbase/pages/_app.js b/examples/with-userbase/pages/_app.js new file mode 100644 index 0000000000000..89a605d5d7fb7 --- /dev/null +++ b/examples/with-userbase/pages/_app.js @@ -0,0 +1,21 @@ +import { useState, useEffect } from 'react' +import userbase from 'userbase-js' +import Layout from '../components/layout' + +import '../styles/index.css' + +function MyApp({ Component, pageProps }) { + const [user, setUser] = useState() + + useEffect(() => { + userbase.init({ appId: process.env.USERBASE_APP_ID }) + }, []) + + return ( + + + + ) +} + +export default MyApp diff --git a/examples/with-userbase/pages/index.js b/examples/with-userbase/pages/index.js new file mode 100644 index 0000000000000..0835540cb5af7 --- /dev/null +++ b/examples/with-userbase/pages/index.js @@ -0,0 +1,18 @@ +import TodoForm from '../components/todo-form' + +function Index({ user }) { + if (user) { + return ( +
    +

    + Welcome, {user.username}! +

    + +
    + ) + } else { + return null + } +} + +export default Index diff --git a/examples/with-userbase/postcss.config.js b/examples/with-userbase/postcss.config.js new file mode 100644 index 0000000000000..23ffee56ffe55 --- /dev/null +++ b/examples/with-userbase/postcss.config.js @@ -0,0 +1,21 @@ +module.exports = { + plugins: [ + 'tailwindcss', + ...(process.env.NODE_ENV === 'production' + ? [ + [ + '@fullhuman/postcss-purgecss', + { + content: [ + './pages/**/*.{js,jsx,ts,tsx}', + './components/**/*.{js,jsx,ts,tsx}', + ], + defaultExtractor: content => + content.match(/[\w-/:]+(?