diff --git a/test/__snapshots__/make.test.ts.snap b/test/__snapshots__/make.test.ts.snap index 994969c01..62cde40fd 100644 --- a/test/__snapshots__/make.test.ts.snap +++ b/test/__snapshots__/make.test.ts.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`create 'none' 'next' 'none': --none_next_none--.gitignore 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--.gitignore 1`] = ` [ - "--none_next_none--.gitignore", + "--none_next-app_none--.gitignore", "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies @@ -43,9 +43,9 @@ next-env.d.ts ] `; -exports[`create 'none' 'next' 'none': --none_next_none--README.md 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--README.md 1`] = ` [ - "--none_next_none--README.md", + "--none_next-app_none--README.md", "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). ## Getting Started @@ -86,9 +86,9 @@ Check out our [Next.js deployment documentation](https://nextjs.org/docs/deploym ] `; -exports[`create 'none' 'next' 'none': --none_next_none--jsconfig.json 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--jsconfig.json 1`] = ` [ - "--none_next_none--jsconfig.json", + "--none_next-app_none--jsconfig.json", "{ "compilerOptions": { "paths": { @@ -100,9 +100,9 @@ exports[`create 'none' 'next' 'none': --none_next_none--jsconfig.json 1`] = ` ] `; -exports[`create 'none' 'next' 'none': --none_next_none--next.config.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--next.config.js 1`] = ` [ - "--none_next_none--next.config.js", + "--none_next-app_none--next.config.js", "/** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, @@ -113,9 +113,9 @@ module.exports = nextConfig; ] `; -exports[`create 'none' 'next' 'none': --none_next_none--package.json 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--package.json 1`] = ` [ - "--none_next_none--package.json", + "--none_next-app_none--package.json", "{ "name": "hello-near", "version": "1.0.0", @@ -163,17 +163,17 @@ exports[`create 'none' 'next' 'none': --none_next_none--package.json 1`] = ` ] `; -exports[`create 'none' 'next' 'none': --none_next_none--public--near.svg 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--public--near.svg 1`] = ` [ - "--none_next_none--public--near.svg", + "--none_next-app_none--public--near.svg", " ", ] `; -exports[`create 'none' 'next' 'none': --none_next_none--public--near-logo.svg 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--public--near-logo.svg 1`] = ` [ - "--none_next_none--public--near-logo.svg", + "--none_next-app_none--public--near-logo.svg", " ", ] `; -exports[`create 'none' 'next' 'none': --none_next_none--public--vercel.svg 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--public--vercel.svg 1`] = ` [ - "--none_next_none--public--vercel.svg", + "--none_next-app_none--public--vercel.svg", "", ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--app.module.css 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--app.module.css 1`] = ` [ - "--none_next_none--src--app--app.module.css", + "--none_next-app_none--src--app--app.module.css", ".main { display: flex; flex-direction: column; @@ -469,9 +469,9 @@ exports[`create 'none' 'next' 'none': --none_next_none--src--app--app.module.css ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--favicon.ico 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--favicon.ico 1`] = ` [ - "--none_next_none--src--app--favicon.ico", + "--none_next-app_none--src--app--favicon.ico", "�PNG  @@ -481,9 +481,9 @@ IHDR@@�iq�SIDATx�՛�m�0�?t��2�Fh4A� � ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--globals.css 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--globals.css 1`] = ` [ - "--none_next_none--src--app--globals.css", + "--none_next-app_none--src--app--globals.css", "@import 'bootstrap'; @import 'bootstrap-icons'; @@ -582,9 +582,9 @@ a { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--hello-components--page.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--hello-components--page.js 1`] = ` [ - "--none_next_none--src--app--hello-components--page.js", + "--none_next-app_none--src--app--hello-components--page.js", "import dynamic from 'next/dynamic'; import styles from '@/app/app.module.css'; @@ -632,9 +632,9 @@ export default function HelloComponents() { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--hello-near--page.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--hello-near--page.js 1`] = ` [ - "--none_next_none--src--app--hello-near--page.js", + "--none_next-app_none--src--app--hello-near--page.js", "'use client'; import { DocsCard, HelloComponentsCard } from '@/components/cards'; import { useWallet } from '@/wallets/wallet-selector'; @@ -703,9 +703,9 @@ export default function HelloNear() { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--layout.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--layout.js 1`] = ` [ - "--none_next_none--src--app--layout.js", + "--none_next-app_none--src--app--layout.js", "'use client'; import './globals.css'; import '@near-wallet-selector/modal-ui/styles.css'; @@ -731,9 +731,9 @@ export default function RootLayout({ children }) { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--app--page.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--app--page.js 1`] = ` [ - "--none_next_none--src--app--page.js", + "--none_next-app_none--src--app--page.js", "import Image from 'next/image'; import styles from './app.module.css'; import { DocsCard, HelloComponentsCard, HelloNearCard } from '@/components/cards'; @@ -775,9 +775,9 @@ export default function Home() { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--components--cards.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--components--cards.js 1`] = ` [ - "--none_next_none--src--components--cards.js", + "--none_next-app_none--src--components--cards.js", "import styles from '../app/app.module.css'; export const DocsCard = () => { @@ -827,9 +827,9 @@ export const HelloComponentsCard = () => { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--components--navigation.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--components--navigation.js 1`] = ` [ - "--none_next_none--src--components--navigation.js", + "--none_next-app_none--src--components--navigation.js", "import Image from 'next/image'; import Link from 'next/link'; import { useEffect, useState } from 'react'; @@ -869,9 +869,9 @@ export const Navigation = () => { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--components--vm-component.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--components--vm-component.js 1`] = ` [ - "--none_next_none--src--components--vm-component.js", + "--none_next-app_none--src--components--vm-component.js", "'use client'; import { useEffect } from 'react'; import { useInitNear, Widget, EthersProviderContext } from 'near-social-vm'; @@ -902,9 +902,9 @@ export default function Component({ src }) { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--config.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--config.js 1`] = ` [ - "--none_next_none--src--config.js", + "--none_next-app_none--src--config.js", "export const NetworkId = 'testnet'; export const HelloNearContract = { @@ -929,9 +929,9 @@ export const ComponentMap = { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--wallets--wallet-selector.js 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--wallets--wallet-selector.js 1`] = ` [ - "--none_next_none--src--wallets--wallet-selector.js", + "--none_next-app_none--src--wallets--wallet-selector.js", "import { create as createStore } from 'zustand'; import { distinctUntilChanged, map } from 'rxjs'; import { providers } from 'near-api-js'; @@ -1055,9 +1055,1417 @@ export function useInitWallet({ createAccessKeyFor, networkId }) { ] `; -exports[`create 'none' 'next' 'none': --none_next_none--src--wallets--web3-wallet.ts 1`] = ` +exports[`create 'none' 'next-app' 'none': --none_next-app_none--src--wallets--web3-wallet.ts 1`] = ` [ - "--none_next_none--src--wallets--web3-wallet.ts", + "--none_next-app_none--src--wallets--web3-wallet.ts", + "'use client'; +import type { EIP1193Provider } from '@web3-onboard/core'; +import injectedModule from '@web3-onboard/injected-wallets'; +import ledgerModule from '@web3-onboard/ledger'; +import { init, useConnectWallet } from '@web3-onboard/react'; +import walletConnectModule from '@web3-onboard/walletconnect'; +import { useEffect, useState } from 'react'; +import { singletonHook } from 'react-singleton-hook'; + +const web3onboardKey = 'web3-onboard:connectedWallets'; + +const wcV2InitOptions: any = { + version: 2, + projectId: '72b7b3359ab477e339a070f615806aa6', + requiredChains: [1, 56], +}; + +const walletConnect = walletConnectModule(wcV2InitOptions); +const ledger = ledgerModule(wcV2InitOptions); +const injected = injectedModule(); + +// initialize Onboard +export const onboard = init({ + wallets: [injected, walletConnect, ledger], + chains: [ + { + id: 1, + token: 'ETH', + label: 'Ethereum Mainnet', + rpcUrl: 'https://rpc.ankr.com/eth', + }, + { + id: 3, + token: 'ETH', + label: 'Ropsten - Ethereum Testnet', + rpcUrl: 'https://rpc.ankr.com/eth_ropsten', + }, + { + id: 5, + token: 'ETH', + label: 'Goerli - Ethereum Testnet', + rpcUrl: 'https://rpc.ankr.com/eth_goerli', + }, + { + id: 10, + token: 'ETH', + label: 'Optimism', + rpcUrl: 'https://rpc.ankr.com/optimism', + }, + { + id: 420, + token: 'ETH', + label: 'Optimism Goerli Testnet', + rpcUrl: 'https://optimism-goerli.publicnode.com', + }, + { + id: 56, + token: 'BNB', + label: 'Binance Smart Chain Mainnet', + rpcUrl: 'https://bsc.publicnode.com', + }, + { + id: 97, + token: 'tBNB', + label: 'Binance Smart Chain Testnet', + rpcUrl: 'https://bsc-testnet.publicnode.com', + }, + { + id: 1313161554, + token: 'ETH', + label: 'Aurora Mainnet', + rpcUrl: 'https://mainnet.aurora.dev', + }, + { + id: 1313161555, + token: 'ETH', + label: 'Aurora Testnet', + rpcUrl: 'https://testnet.aurora.dev', + }, + { + id: 137, + token: 'MATIC', + label: 'Polygon Mainnet', + rpcUrl: 'https://rpc.ankr.com/polygon', + }, + { + id: 80001, + token: 'MATIC', + label: 'Polygon Testnet Mumbai', + rpcUrl: 'https://rpc.ankr.com/polygon_mumbai', + }, + { + id: 280, + token: 'ETH', + label: 'zkSync Era Testnet', + rpcUrl: 'https://testnet.era.zksync.dev', + }, + { + id: 324, + token: 'ETH', + label: 'zkSync Era Mainnet', + rpcUrl: 'https://zksync2-mainnet.zksync.io', + }, + { + id: 1101, + token: 'ETH', + label: 'Polygon zkEVM', + rpcUrl: 'https://zkevm-rpc.com', + }, + { + id: 1442, + token: 'ETH', + label: 'Polygon zkEVM Testnet', + rpcUrl: 'https://rpc.public.zkevm-test.net', + }, + { + id: 42161, + token: 'ETH', + label: 'Arbitrum One Mainnet', + rpcUrl: 'https://arb1.arbitrum.io/rpc', + }, + { + id: 42170, + token: 'ETH', + label: 'Arbitrum Nova', + rpcUrl: 'https://nova.arbitrum.io/rpc', + }, + { + id: 421613, + token: 'AGOR', + label: 'Arbitrum Goerli', + rpcUrl: 'https://goerli-rollup.arbitrum.io/rpc', + }, + { + id: 25, + token: 'CRO', + label: 'Cronos Mainnet Beta', + rpcUrl: 'https://evm.cronos.org', + }, + { + id: 338, + token: 'TCRO', + label: 'Cronos Testnet', + rpcUrl: 'https://evm-t3.cronos.org', + }, + { + id: 100, + token: 'XDAI', + label: 'Gnosis', + rpcUrl: 'https://rpc.ankr.com/gnosis', + }, + { + id: 10200, + token: 'XDAI', + label: 'Gnosis Chiado Testnet', + rpcUrl: 'https://rpc.chiadochain.net', + }, + { + id: 42220, + token: 'CELO', + label: 'Celo Mainnet', + rpcUrl: 'https://rpc.ankr.com/celo', + }, + { + id: 44787, + token: 'CELO', + label: 'Celo Alfajores Testnet', + rpcUrl: 'https://alfajores-forno.celo-testnet.org', + }, + { + id: 43114, + token: 'AVAX', + label: 'Avalanche C-Chain', + rpcUrl: 'https://rpc.ankr.com/avalanche', + }, + { + id: 43113, + token: 'AVAX', + label: 'Avalanche Fuji Testnet', + rpcUrl: 'https://rpc.ankr.com/avalanche_fuji', + }, + { + id: 250, + token: 'FTM', + label: 'Fantom Opera', + rpcUrl: 'https://rpc.ankr.com/fantom', + }, + { + id: 4002, + token: 'FTM', + label: 'Fantom Testnet', + rpcUrl: 'https://rpc.ankr.com/fantom_testnet', + }, + { + id: 1284, + token: 'GLMR', + label: 'Moonbeam', + rpcUrl: 'https://rpc.ankr.com/moonbeam', + }, + { + id: 61, + token: 'ETC', + label: 'Ethereum Classic Mainnet', + rpcUrl: 'https://etc.rivet.link', + }, + { + id: 84531, + token: 'ETH', + label: 'Base Goerli Testnet', + rpcUrl: 'https://goerli.base.org', + }, + { + id: 8453, + token: 'ETH', + label: 'Base', + rpcUrl: 'https://mainnet.base.org', + }, + { + id: 5001, + token: 'MNT', + label: 'Mantle Testnet', + rpcUrl: 'https://rpc.testnet.mantle.xyz', + }, + { + id: 5000, + token: 'MNT', + label: 'Mantle', + rpcUrl: 'https://rpc.mantle.xyz', + }, + ], + appMetadata: { + name: 'NEAR', + icon: '/next.svg', + description: 'NEAR', + }, + theme: 'dark', + containerElements: { + // connectModal: '#near-social-navigation-bar', + // accountCenter: "#near-social-web3-account", + }, +}); + +type EthersProviderContext = { + provider?: EIP1193Provider; + useConnectWallet: typeof useConnectWallet; +}; + +const defaultEthersProviderContext: EthersProviderContext = { useConnectWallet }; + +export const useEthersProviderContext = singletonHook(defaultEthersProviderContext, () => { + const [{ wallet }] = useConnectWallet(); + const [ethersProvider, setEthersProvider] = useState(defaultEthersProviderContext); + + useEffect(() => { + (async () => { + if (typeof localStorage === 'undefined') return; + + const walletsSub = onboard.state.select('wallets'); + + walletsSub.subscribe((wallets) => { + const connectedWallets = wallets.map(({ label }) => label); + localStorage.setItem(web3onboardKey, JSON.stringify(connectedWallets)); + }); + + const previouslyConnectedWallets = JSON.parse(localStorage.getItem(web3onboardKey) || '[]'); + + if (previouslyConnectedWallets) { + // You can also auto connect "silently" and disable all onboard modals to avoid them flashing on page load + await onboard.connectWallet({ + autoSelect: { + label: previouslyConnectedWallets[0], + disableModals: true, + }, + }); + } + })(); + }, []); + + useEffect(() => { + if (!wallet) return; + + setEthersProvider({ + provider: wallet.provider, + useConnectWallet, + }); + }, [wallet]); + + return ethersProvider; +});", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--.gitignore 1`] = ` +[ + "--none_next-page_none--.gitignore", + "# 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 +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--README.md 1`] = ` +[ + "--none_next-page_none--README.md", + "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). + +## Getting Started + +First, run the development server: + +\`\`\`bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +\`\`\` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying \`app/page.js\`. The page auto-updates as you edit the file. + +This project uses [\`next/font\`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## 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. +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--jsconfig.json 1`] = ` +[ + "--none_next-page_none--jsconfig.json", + "{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + } +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--next.config.js 1`] = ` +[ + "--none_next-page_none--next.config.js", + "/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig; +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--package.json 1`] = ` +[ + "--none_next-page_none--package.json", + "{ + "name": "hello-near", + "version": "1.0.0", + "private": true, + "engines": { + "node": ">=18" + }, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@near-wallet-selector/core": "^8.5.1", + "@near-wallet-selector/here-wallet": "^8.5.1", + "@near-wallet-selector/modal-ui": "^8.5.1", + "@near-wallet-selector/my-near-wallet": "^8.5.1", + "@web3-onboard/core": "^2.20.2", + "@web3-onboard/injected-wallets": "^2.10.1", + "@web3-onboard/ledger": "^2.4.6", + "@web3-onboard/react": "^2.8.7", + "@web3-onboard/walletconnect": "^2.3.9", + "base64-js": "^1.5.1", + "bootstrap": "^5.3.2", + "bootstrap-icons": "^1.11.1", + "ieee754": "^1.2.1", + "near-api-js": "^2.1.3", + "near-social-vm": "github:NearSocial/VM#2.5.2", + "next": "14.0.1", + "pino-pretty": "^10.2.3", + "react": "^18", + "react-bootstrap": "2.9.1", + "react-bootstrap-icons": "^1.10.3", + "react-dom": "^18", + "react-singleton-hook": "^4.0.1", + "zustand": "^4.4.4" + }, + "devDependencies": { + "eslint": "^8.53", + "eslint-config-next": "14.0.1" + } +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--public--favicon.ico 1`] = ` +[ + "--none_next-page_none--public--favicon.ico", + "�PNG + + +IHDR@@�iq�SIDATx�՛�m�0�?t��2�Fh4A� � �����Gp7P6P7\`d�6M�<�b~�O��O'�"%ý� ��i�t��3��g\`$3���'��^��V��0l?�N/��������ev[g�M�RW���\\o�wA���HZ�8�49��L��K�Qq�s;������ö�^�S\\VI���� ]a�&�d��J��g������;�?�V0�� a�6�RUP� K �c�#w��@���c�l.�]��9ܳ� �mO���%�c�eWV� Ѯ �x ��n��\`z\`�T���&@�5C�f��3H��� �(q�� +�k�9C��/�&@=gh�9çX I$u��p�ft,�����34�t�?/��/Tr�aW���±g� +@,�Ԧ��-���3� ���@� � �����:�g�W���;K��X�P�d?O��Xz_�{ۄ�rs�Wx�,@�L8֯��K�\\mu3���SZ�1��D<��\`�#}U�"(wU#y��5J?&�3H&Q������J��:g��,������J?����,��z��U8�d�$u3�J?��J\\U�.�PZ�P<�:� 3��� �/���>6���������l�ҏ�gc羨h��c�:���\`��=]-�BX��cZx̳���)�6�!�#�d��C L�W���;@�M233IEND�B\`�", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--public--near.svg 1`] = ` +[ + "--none_next-page_none--public--near.svg", + " +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--public--near-logo.svg 1`] = ` +[ + "--none_next-page_none--public--near-logo.svg", + " + + + + + + +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--public--next.svg 1`] = ` +[ + "--none_next-page_none--public--next.svg", + "", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--public--vercel.svg 1`] = ` +[ + "--none_next-page_none--public--vercel.svg", + "", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--components--cards.js 1`] = ` +[ + "--none_next-page_none--src--components--cards.js", + "import styles from "../styles/app.module.css"; + +export const DocsCard = () => { + return ( + +

+ Near Docs -> +

+

Learn how this application works, and what you can build on Near.

+
+ ); +}; + +export const HelloNearCard = () => { + return ( + +

+ Near Integration -> +

+

Discover how simple it is to interact with a Near smart contract.

+
+ ); +}; + +export const HelloComponentsCard = () => { + return ( + +

+ Web3 Components -> +

+

See how Web3 components can help you to create multi-chain apps.

+
+ ); +}; +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--components--navigation.js 1`] = ` +[ + "--none_next-page_none--src--components--navigation.js", + "import Image from 'next/image'; +import Link from 'next/link'; +import { useEffect, useState } from 'react'; + +import NearLogo from 'public/near-logo.svg'; +import { useWallet } from '@/wallets/wallet-selector'; + +export const Navigation = () => { + + const { signedAccountId, logOut, logIn } = useWallet(); + const [action, setAction] = useState(() => { }); + const [label, setLabel] = useState('Loading...'); + + useEffect(() => { + if (signedAccountId) { + setAction(() => logOut); + setLabel(\`Logout \${signedAccountId}\`); + } else { + setAction(() => logIn); + setLabel('Login'); + } + }, [signedAccountId, logOut, logIn, setAction, setLabel]); + + return ( + + ); +};", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--components--vm-component.js 1`] = ` +[ + "--none_next-page_none--src--components--vm-component.js", + "'use client'; +import { useEffect } from 'react'; +import { useInitNear, Widget, EthersProviderContext } from 'near-social-vm'; + +import { useWallet } from '@/wallets/wallet-selector'; +import { useEthersProviderContext } from '@/wallets/web3-wallet'; +import { NetworkId } from '@/config'; + +export default function Component({ src }) { + const ethersContext = useEthersProviderContext(); + const { selector } = useWallet(); + const { initNear } = useInitNear(); + + useEffect(() => { + initNear && selector && initNear({ networkId: NetworkId, selector }); + }, [initNear, selector]); + + return ( +
+ + + +

Source: {src}

+
+ ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--config.js 1`] = ` +[ + "--none_next-page_none--src--config.js", + "export const NetworkId = 'testnet'; + +export const HelloNearContract = { + mainnet: 'hello.near-examples.near', + testnet: 'hello.near-examples.testnet', +} + +export const ComponentMap = { + mainnet: { + socialDB: 'social.near', + Lido: 'zavodil.near/widget/Lido', + HelloNear: 'gagdiez.near/widget/HelloNear', + LoveNear: 'gagdiez.near/widget/LoveNear', + }, + testnet: { + socialDB: 'v1.social08.testnet', + Lido: 'influencer.testnet/widget/Lido', + HelloNear: 'influencer.testnet/widget/HelloNear', + LoveNear: 'influencer.testnet/widget/LoveNear', + } +} ", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--layout.js 1`] = ` +[ + "--none_next-page_none--src--layout.js", + ""use client"; +import "@near-wallet-selector/modal-ui/styles.css"; + +import { NetworkId } from "@/config"; +import { Navigation } from "@/components/navigation"; +import { useInitWallet } from "@/wallets/wallet-selector"; + +export default function RootLayout({ children }) { + useInitWallet({ createAccessKeyFor: "", networkId: NetworkId }); + + return ( + <> + + {children} + + ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--pages--_app.js 1`] = ` +[ + "--none_next-page_none--src--pages--_app.js", + "import RootLayout from "@/layout"; +import "@/styles/globals.css"; + +export default function MyApp({ Component, pageProps }) { + return ( + + + + ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--pages--_document.js 1`] = ` +[ + "--none_next-page_none--src--pages--_document.js", + "import Document, { Html, Head, Main, NextScript } from "next/document"; + +class MyDocument extends Document { + render() { + return ( + + + +
+ + + + ); + } +} + +export default MyDocument; +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--pages--hello-components--index.js 1`] = ` +[ + "--none_next-page_none--src--pages--hello-components--index.js", + "import dynamic from "next/dynamic"; + +import styles from "@/styles/app.module.css"; +import { DocsCard, HelloNearCard } from "@/components/cards"; +import { NetworkId, ComponentMap } from "@/config"; + +const Component = dynamic(() => import("@/components/vm-component"), { + ssr: false, +}); + +const socialComponents = ComponentMap[NetworkId]; + +export default function HelloComponents() { + return ( + <> +
+
+

+ Loading components from:   + {socialComponents.socialDB} +

+
+
+

+ {" "} + Multi-chain Components Made Simple{" "} +

+
+
+
+ +

 

+ +
+
+ +
+
+
+ +
+ + +
+
+ + ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--pages--hello-near--index.js 1`] = ` +[ + "--none_next-page_none--src--pages--hello-near--index.js", + ""use client"; +import { DocsCard, HelloComponentsCard } from "@/components/cards"; +import { useWallet } from "@/wallets/wallet-selector"; +import { useState, useEffect } from "react"; +import { HelloNearContract, NetworkId } from "../../config"; +import styles from "@/styles/app.module.css"; + +// Contract that the app will interact with +const CONTRACT = HelloNearContract[NetworkId]; + +export default function HelloNear() { + const { signedAccountId, viewMethod, callMethod } = useWallet(); + + const [greeting, setGreeting] = useState("loading..."); + const [loggedIn, setLoggedIn] = useState(false); + const [showSpinner, setShowSpinner] = useState(false); + + useEffect(() => { + viewMethod && + viewMethod(CONTRACT, "get_greeting", {}).then((greeting) => + setGreeting(greeting) + ); + }, [viewMethod]); + + useEffect(() => { + setLoggedIn(!!signedAccountId); + }, [signedAccountId]); + + const saveGreeting = async () => { + setShowSpinner(true); + await callMethod(CONTRACT, "set_greeting", { greeting }); + setShowSpinner(false); + }; + + return ( +
+
+

+ Interacting with the contract:   + {CONTRACT} +

+
+ +
+

+ {" "} + The contract says: {greeting}{" "} +

+ + +
+
+ + +
+
+ ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--pages--index.js 1`] = ` +[ + "--none_next-page_none--src--pages--index.js", + "import Image from "next/image"; +import styles from "@/styles/app.module.css"; +import { + DocsCard, + HelloComponentsCard, + HelloNearCard, +} from "@/components/cards"; + +export default function Home() { + return ( +
+
+ +
+ Next.js Logo +

+

+ Next.js Logo +
+ +
+ + + +
+
+ ); +} +", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--styles--app.module.css 1`] = ` +[ + "--none_next-page_none--src--styles--app.module.css", + ".main { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 6rem; + min-height: 100vh; +} + +.description { + display: inherit; + justify-content: inherit; + align-items: inherit; + font-size: 0.85rem; + max-width: var(--max-width); + width: 100%; + z-index: 2; + font-family: var(--font-mono); +} + +.description a { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; +} + +.description p { + position: relative; + margin: 0; + padding: 1rem; + background-color: rgba(var(--callout-rgb), 0.5); + border: 1px solid rgba(var(--callout-border-rgb), 0.3); + border-radius: var(--border-radius); +} + +.code { + font-weight: 700; + font-family: var(--font-mono); +} + +.grid { + display: grid; + grid-template-columns: repeat(2, minmax(25%, auto)); + max-width: 100%; + width: var(--max-width); +} + +.card { + padding: 1rem 1.2rem; + border-radius: var(--border-radius); + background: rgba(var(--card-rgb), 0); + border: 1px solid rgba(var(--card-border-rgb), 0); + transition: background 200ms, border 200ms; +} + +.card span { + display: inline-block; + transition: transform 200ms; +} + +.card h2 { + font-weight: 600; + margin-bottom: 0.7rem; +} + +.card p { + margin: 0; + opacity: 0.6; + font-size: 0.9rem; + line-height: 1.5; + max-width: 30ch; +} + +.center { + display: flex; + justify-content: center; + align-items: center; + position: relative; + padding: 4rem 0; + width: 100%; +} + +.center::before { + background: var(--secondary-glow); + border-radius: 50%; + width: 480px; + height: 360px; + margin-left: -400px; +} + +.center::after { + background: var(--primary-glow); + width: 240px; + height: 180px; + z-index: -1; +} + +.center::before, +.center::after { + content: ''; + left: 50%; + position: absolute; + filter: blur(45px); + transform: translateZ(0); + opacity: 0.3; +} + +.logo { + position: relative; +} + +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + .card:hover { + background: rgba(var(--card-rgb), 0.1); + border: 1px solid rgba(var(--card-border-rgb), 0.15); + } + + .card:hover span { + transform: translateX(4px); + } +} + +@media (prefers-reduced-motion) { + .card:hover span { + transform: none; + } +} + +/* Mobile */ +@media (max-width: 700px) { + .content { + padding: 4rem; + } + + .grid { + grid-template-columns: 1fr; + margin-bottom: 120px; + max-width: 320px; + text-align: center; + } + + .card { + padding: 1rem 2.5rem; + } + + .card h2 { + margin-bottom: 0.5rem; + } + + .center { + padding: 8rem 0 6rem; + } + + .center::before { + transform: none; + height: 300px; + } + + .description { + font-size: 0.8rem; + } + + .description a { + padding: 1rem; + } + + .description p, + .description div { + display: flex; + justify-content: center; + width: 100%; + } + + .description p { + align-items: center; + inset: 0 0 auto; + padding: 2rem 1rem 1.4rem; + border-radius: 0; + border: none; + border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); + background: linear-gradient(to bottom, + rgba(var(--background-start-rgb), 1), + rgba(var(--callout-rgb), 0.5)); + background-clip: padding-box; + backdrop-filter: blur(24px); + } + + .description div { + align-items: flex-end; + pointer-events: none; + inset: auto 0 0; + padding: 2rem; + height: 200px; + background: linear-gradient(to bottom, + transparent 0%, + rgb(var(--background-end-rgb)) 40%); + z-index: 1; + } +} + +/* Tablet and Smaller Desktop */ +@media (min-width: 701px) and (max-width: 1120px) { + .grid { + grid-template-columns: repeat(2, 50%); + } +} + +@media (prefers-color-scheme: dark) { + .vercelLogo { + filter: invert(1); + } + + .logo { + filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); + } +} + +@keyframes rotate { + from { + transform: rotate(360deg); + } + + to { + transform: rotate(0deg); + } +}", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--styles--globals.css 1`] = ` +[ + "--none_next-page_none--src--styles--globals.css", + "@import 'bootstrap'; +@import 'bootstrap-icons'; + +:root { + --max-width: 1100px; + --border-radius: 12px; + + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; + + --primary-glow: conic-gradient(from 180deg at 50% 50%, + #16abff33 0deg, + #0885ff33 55deg, + #54d6ff33 120deg, + #0071ff33 160deg, + transparent 360deg); + --secondary-glow: radial-gradient(rgba(255, 255, 255, 1), + rgba(255, 255, 255, 0)); + + --tile-start-rgb: 239, 245, 249; + --tile-end-rgb: 228, 232, 233; + --tile-border: conic-gradient(#00000080, + #00000040, + #00000030, + #00000020, + #00000010, + #00000010, + #00000080); + + --callout-rgb: 238, 240, 241; + --callout-border-rgb: 172, 175, 176; + --card-rgb: 180, 185, 188; + --card-border-rgb: 131, 134, 135; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + + --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); + --secondary-glow: linear-gradient(to bottom right, + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0.3)); + + --tile-start-rgb: 2, 13, 46; + --tile-end-rgb: 2, 5, 19; + --tile-border: conic-gradient(#ffffff80, + #ffffff40, + #ffffff30, + #ffffff20, + #ffffff10, + #ffffff10, + #ffffff80); + + --callout-rgb: 20, 20, 20; + --callout-border-rgb: 108, 108, 108; + --card-rgb: 100, 100, 100; + --card-border-rgb: 200, 200, 200; + } +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + color: rgb(var(--foreground-rgb)); + background: linear-gradient(to bottom, + transparent, + rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb)); + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Noto Sans, Ubuntu, Droid Sans, Helvetica Neue, sans-serif; +} + +a { + color: inherit; + text-decoration: none; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } +}", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--wallets--wallet-selector.js 1`] = ` +[ + "--none_next-page_none--src--wallets--wallet-selector.js", + "import { create as createStore } from 'zustand'; +import { distinctUntilChanged, map } from 'rxjs'; +import { providers } from 'near-api-js'; +import { setupWalletSelector } from '@near-wallet-selector/core'; +import { setupModal } from '@near-wallet-selector/modal-ui'; +import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet'; +import { setupHereWallet } from '@near-wallet-selector/here-wallet'; + +import { useEffect, useState } from 'react'; + +export const useWallet = createStore(set => ({ + signedAccountId: '', + logOut: undefined, + logIn: undefined, + selector: undefined, + viewMethod: undefined, + callMethod: undefined, + setLogActions: ({ logOut, logIn }) => set({ logOut, logIn }), + setAuth: ({ signedAccountId }) => set({ signedAccountId }), + setMethods: ({ viewMethod, callMethod }) => set({ viewMethod, callMethod }), + setStoreSelector: ({ selector }) => set({ selector }), +})); + +export function useInitWallet({ createAccessKeyFor, networkId }) { + const setAuth = useWallet(store => store.setAuth); + const setLogActions = useWallet(store => store.setLogActions); + const setMethods = useWallet(store => store.setMethods); + const setStoreSelector = useWallet(store => store.setStoreSelector); + const [selector, setSelector] = useState(undefined); + + useEffect(() => { + const selector = setupWalletSelector({ + network: networkId, + modules: [setupMyNearWallet(), setupHereWallet()] + }); + + setSelector(selector); + setStoreSelector({ selector }); + }, [networkId, setStoreSelector]); + + useEffect(() => { + if (!selector) return; + + selector.then(walletSelector => { + const accounts = walletSelector.store.getState().accounts; + const signedAccountId = accounts.find((account) => account.active)?.accountId || ''; + setAuth({ signedAccountId }); + + walletSelector.store.observable + .pipe( + map((state) => state.accounts), + distinctUntilChanged() + ) + .subscribe((accounts) => { + const signedAccountId = accounts.find((account) => account.active)?.accountId || ''; + setAuth({ signedAccountId }); + }); + }); + }, [selector, setAuth]); + + useEffect(() => { + if (!selector) return; + + // defined logOut and logIn actions + const logOut = async () => { + const wallet = await (await selector).wallet(); + await wallet.signOut(); + setAuth({ signedAccountId: '' }); + }; + + const logIn = async () => { + const modal = setupModal(await selector, { contractId: createAccessKeyFor }); + modal.show(); + }; + + setLogActions({ logOut, logIn }); + }, [createAccessKeyFor, selector, setAuth, setLogActions]); + + useEffect(() => { + if (!selector) return; + + const viewMethod = async (contractId, method, args = {}) => { + const { network } = (await selector).options; + const provider = new providers.JsonRpcProvider({ url: network.nodeUrl }); + + let res = await provider.query({ + request_type: 'call_function', + account_id: contractId, + method_name: method, + args_base64: Buffer.from(JSON.stringify(args)).toString('base64'), + finality: 'optimistic', + }); + return JSON.parse(Buffer.from(res.result).toString()); + }; + + const callMethod = async (contractId, method, args = {}, gas = '30000000000000', deposit = 0) => { + const wallet = await (await selector).wallet(); + + const outcome = await wallet.signAndSendTransaction({ + receiverId: contractId, + actions: [ + { + type: 'FunctionCall', + params: { + methodName: method, + args, + gas, + deposit, + }, + }, + ], + }); + + return providers.getTransactionLastResult(outcome); + }; + + setMethods({ viewMethod, callMethod }); + + }, [selector, setMethods]); +}", +] +`; + +exports[`create 'none' 'next-page' 'none': --none_next-page_none--src--wallets--web3-wallet.ts 1`] = ` +[ + "--none_next-page_none--src--wallets--web3-wallet.ts", "'use client'; import type { EIP1193Provider } from '@web3-onboard/core'; import injectedModule from '@web3-onboard/injected-wallets'; diff --git a/test/__snapshots__/user-input.test.ts.snap b/test/__snapshots__/user-input.test.ts.snap index c2a6eebaf..d242883b3 100644 --- a/test/__snapshots__/user-input.test.ts.snap +++ b/test/__snapshots__/user-input.test.ts.snap @@ -54,12 +54,12 @@ exports[`messages snapshot messages with params 1`] = ` ] `; -exports[`test success message test matrix 'none' 'next' 'none' false 1`] = ` +exports[`test success message test matrix 'none' 'next-app' 'none' false 1`] = ` [ [ " ====================================================== -✅ Success! Created 'my_project_name', a gateway using NextJS + React. +✅ Success! Created 'my_project_name', a gateway using NextJS (App Router). Next steps: @@ -73,12 +73,49 @@ exports[`test success message test matrix 'none' 'next' 'none' false 1`] = ` ] `; -exports[`test success message test matrix 'none' 'next' 'none' true 1`] = ` +exports[`test success message test matrix 'none' 'next-app' 'none' true 1`] = ` [ [ " ====================================================== -✅ Success! Created 'my_project_name', a gateway using NextJS + React. +✅ Success! Created 'my_project_name', a gateway using NextJS (App Router). + +Next steps: + + - Navigate to your project: + cd my_project_name +Then: + - Start your app: + pnpm run dev", + ], +] +`; + +exports[`test success message test matrix 'none' 'next-page' 'none' false 1`] = ` +[ + [ + " +====================================================== +✅ Success! Created 'my_project_name', a gateway using NextJS (Classic). + +Next steps: + + - Navigate to your project: + cd my_project_name + - Install all dependencies + pnpm install + - Start your app: + pnpm run dev", + ], +] +`; + +exports[`test success message test matrix 'none' 'next-page' 'none' true 1`] = ` +[ + [ + " +====================================================== +✅ Success! Created 'my_project_name', a gateway using NextJS (Classic). Next steps: diff --git a/test/make.test.ts b/test/make.test.ts index 6ee80f94e..ef336c458 100644 --- a/test/make.test.ts +++ b/test/make.test.ts @@ -53,7 +53,7 @@ describe('create contract', () => { describe('create', () => { const contracts: Contract[] = ['none']; - const frontends: Frontend[] = ['next', 'vanilla']; + const frontends: Frontend[] = ['next-app', 'next-page', 'vanilla']; const tests: TestingFramework[] = ['none']; // all combinations of the above const testMatrix = contracts.flatMap(c => frontends.flatMap(f => tests.map(t => ([c, f, t])))); diff --git a/test/user-input.test.ts b/test/user-input.test.ts index 44dc996dd..fff1b785e 100644 --- a/test/user-input.test.ts +++ b/test/user-input.test.ts @@ -24,7 +24,8 @@ describe('messages', () => { show.successContractToText('ts'); show.successContractToText('rs'); - show.successFrontendToText('next'); + show.successFrontendToText('next-page'); + show.successFrontendToText('next-app'); show.successFrontendToText('vanilla'); show.successFrontendToText('none'); @@ -59,7 +60,7 @@ describe('test success message', () => { describe('test success message', () => { let showSpy; const contracts: Contract[] = ['none']; - const frontends: Frontend[] = ['next', 'vanilla']; + const frontends: Frontend[] = ['next-page', 'next-app', 'vanilla']; const tests: TestingFramework[] = ['none']; const install = [true, false]; // all combinations of the above