create-bch-dapp 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -0
- package/package.json +33 -0
- package/templates/nextjs/README.md +36 -0
- package/templates/nextjs/_gitignore +41 -0
- package/templates/nextjs/app/BCHConnectWrapper.tsx +35 -0
- package/templates/nextjs/app/favicon.ico +0 -0
- package/templates/nextjs/app/globals.css +220 -0
- package/templates/nextjs/app/layout.tsx +33 -0
- package/templates/nextjs/app/page.tsx +174 -0
- package/templates/nextjs/next-env.d.ts +6 -0
- package/templates/nextjs/next.config.ts +7 -0
- package/templates/nextjs/package.json +31 -0
- package/templates/nextjs/public/bch.svg +17 -0
- package/templates/nextjs/public/next.svg +20 -0
- package/templates/nextjs/public/react.svg +1 -0
- package/templates/nextjs/tsconfig.json +34 -0
- package/templates/react-ts-vite/README.md +75 -0
- package/templates/react-ts-vite/_gitignore +24 -0
- package/templates/react-ts-vite/eslint.config.js +23 -0
- package/templates/react-ts-vite/index.html +13 -0
- package/templates/react-ts-vite/package.json +32 -0
- package/templates/react-ts-vite/public/vite.svg +1 -0
- package/templates/react-ts-vite/src/App.css +138 -0
- package/templates/react-ts-vite/src/App.tsx +153 -0
- package/templates/react-ts-vite/src/assets/bch.svg +17 -0
- package/templates/react-ts-vite/src/assets/react.svg +1 -0
- package/templates/react-ts-vite/src/bchConnect.ts +13 -0
- package/templates/react-ts-vite/src/index.css +74 -0
- package/templates/react-ts-vite/src/main.tsx +14 -0
- package/templates/react-ts-vite/tsconfig.app.json +28 -0
- package/templates/react-ts-vite/tsconfig.json +7 -0
- package/templates/react-ts-vite/tsconfig.node.json +26 -0
- package/templates/react-ts-vite/vite.config.ts +13 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import d from"fs";import m from"fs/promises";import c from"path";import{spawn as _}from"child_process";import s from"kleur";import g from"ora";import{input as j,select as p}from"@inquirer/prompts";import{fileURLToPath as k}from"url";var T="2684b13f5add72d95b5cf00ddea3dd4f",f={reactVite:{label:"React + Vite",path:"../templates/react-ts-vite"},nextjs:{label:"Next.js",path:"../templates/nextjs"}},C=k(import.meta.url),x=c.dirname(C);function N(e){return d.existsSync(e)?d.readdirSync(e).length===0:!0}function R(e){return e.trim().toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9._-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}async function v(e,a){await m.mkdir(a,{recursive:!0});let t=await m.readdir(e,{withFileTypes:!0});for(let r of t){let n=c.join(e,r.name),o=c.join(a,r.name);new Set(["node_modules",".next","dist",".git",".DS_Store","bun.lockb","package-lock.json","pnpm-lock.yaml","yarn.lock"]).has(r.name)||(r.isDirectory()?await v(n,o):r.isFile()&&(r.name==="_gitignore"?await m.copyFile(n,c.join(a,".gitignore")):await m.copyFile(n,o)))}}async function S(e,a,t){let r=t==="nextjs"?".env.local":".env",n=c.join(e,r),o=`# BCH Connect starter
|
|
3
|
+
VITE_BCH_NETWORK=${a.network}
|
|
4
|
+
VITE_REOWN_PROJECT_ID=${a.projectId}
|
|
5
|
+
`,i=`# BCH Connect starter
|
|
6
|
+
NEXT_PUBLIC_BCH_NETWORK=${a.network}
|
|
7
|
+
NEXT_PUBLIC_REOWN_PROJECT_ID=${a.projectId}
|
|
8
|
+
`,u=t==="reactVite"?o:i;await m.writeFile(n,u,"utf8")}async function D(e,a){let t=c.join(e,"package.json"),r=await m.readFile(t,"utf8"),n=JSON.parse(r);n.name=R(a),n.dependencies&&typeof n.dependencies=="object"&&"bch-connect"in n.dependencies&&(n.dependencies["bch-connect"]="latest"),await m.writeFile(t,JSON.stringify(n,null,2)+`
|
|
9
|
+
`,"utf8")}async function h(e,a,t,{silent:r=!1}={}){return new Promise(n=>{_(a,t,{cwd:e,stdio:r?"ignore":"inherit",shell:process.platform==="win32"}).on("close",i=>n(i??1))})}function O(e){switch(e){case"bun":return{cmd:"bun",args:["install"]};case"pnpm":return{cmd:"pnpm",args:["install"]};case"yarn":return{cmd:"yarn",args:["install"]};case"npm":default:return{cmd:"npm",args:["install"]}}}function F(e){switch(e){case"bun":return{cmd:"bun",args:["run","dev"]};case"pnpm":return{cmd:"pnpm",args:["dev"]};case"yarn":return{cmd:"yarn",args:["dev"]};case"npm":default:return{cmd:"npm",args:["run","dev"]}}}async function $(){let a=process.argv[2]?.trim()||await j({message:"Your project name",default:"my-bch-dapp"}),t=c.resolve(process.cwd(),a);d.existsSync(t)&&!N(t)&&(console.error(s.red(`\u2716 Target directory already exists and is not empty: ${t}`)),process.exit(1));let r=await p({message:"Choose a template",default:"reactVite",choices:[{name:f.reactVite.label,value:"reactVite"},{name:f.nextjs.label,value:"nextjs"}]}),n=c.resolve(x,f[r].path);d.existsSync(n)||(console.error(s.red(`Template not found at: ${n}`)),process.exit(1));let o=await p({message:"Package manager",default:"bun",choices:[{name:"bun",value:"bun"},{name:"npm",value:"npm"},{name:"pnpm",value:"pnpm"},{name:"yarn",value:"yarn"}]}),i=await p({message:"Reown Project ID",default:"default",choices:[{name:"Use public ID (localhost only)",value:"default"},{name:"Enter my own ID (required for production)",value:"custom"}]}),u=i==="custom"?await j({message:"Paste your Reown Project ID",validate(l){return l.trim()?l.trim().length<16?"That does not look like a valid Project ID.":!0:"Project ID is required."}}):T,P=await p({message:"Network",default:"mainnet",choices:[{name:"Mainnet",value:"mainnet"},{name:"Testnet",value:"testnet"}]}),w=g("Creating project\u2026").start();try{await v(n,t),await D(t,a),await S(t,{projectId:u,network:P},r),w.succeed("Project created")}catch(l){w.fail("Failed to create project"),console.error(l),process.exit(1)}{let{cmd:l,args:y}=O(o);g(`Installing dependencies (${o})\u2026`).start().stop(),await h(t,l,y)!==0&&(console.error(s.red(`
|
|
10
|
+
\u2716 Install failed. Run it manually:
|
|
11
|
+
cd ${a}
|
|
12
|
+
${l} ${y.join(" ")}
|
|
13
|
+
`)),process.exit(1)),g().succeed("Dependencies installed")}console.log(""),console.log(s.green().bold("\u2713 Starting dev server\u2026")),console.log(s.dim(` (running in ${t})`)),console.log(s.dim(` Press Ctrl+C to stop.
|
|
14
|
+
`)),i==="default"&&(console.log(s.yellow("Note:")+" Using a public localhost-only Reown Project ID. Replace it before production."),console.log(s.dim(" Update `.env` and create your own Project ID at: https://dashboard.reown.com/\n")));let{cmd:b,args:I}=F(o),E=await h(t,b,I);process.exit(E)}$().catch(e=>{console.error(s.red(String(e))),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-bch-dapp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-bch-dapp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "bun run src/index.ts",
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"build:prod": "tsup --minify",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"test": "vitest"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@inquirer/prompts": "^8.1.0",
|
|
22
|
+
"kleur": "^4.1.5",
|
|
23
|
+
"ora": "^9.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^25.0.3",
|
|
27
|
+
"tsup": "^8.5.1",
|
|
28
|
+
"typescript": "^5.0.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
First, run the development server:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev
|
|
9
|
+
# or
|
|
10
|
+
yarn dev
|
|
11
|
+
# or
|
|
12
|
+
pnpm dev
|
|
13
|
+
# or
|
|
14
|
+
bun dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
+
|
|
19
|
+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
20
|
+
|
|
21
|
+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
22
|
+
|
|
23
|
+
## Learn More
|
|
24
|
+
|
|
25
|
+
To learn more about Next.js, take a look at the following resources:
|
|
26
|
+
|
|
27
|
+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
28
|
+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
29
|
+
|
|
30
|
+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
31
|
+
|
|
32
|
+
## Deploy on Vercel
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
+
|
|
3
|
+
# dependencies
|
|
4
|
+
/node_modules
|
|
5
|
+
/.pnp
|
|
6
|
+
.pnp.*
|
|
7
|
+
.yarn/*
|
|
8
|
+
!.yarn/patches
|
|
9
|
+
!.yarn/plugins
|
|
10
|
+
!.yarn/releases
|
|
11
|
+
!.yarn/versions
|
|
12
|
+
|
|
13
|
+
# testing
|
|
14
|
+
/coverage
|
|
15
|
+
|
|
16
|
+
# next.js
|
|
17
|
+
/.next/
|
|
18
|
+
/out/
|
|
19
|
+
|
|
20
|
+
# production
|
|
21
|
+
/build
|
|
22
|
+
|
|
23
|
+
# misc
|
|
24
|
+
.DS_Store
|
|
25
|
+
*.pem
|
|
26
|
+
|
|
27
|
+
# debug
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
.pnpm-debug.log*
|
|
32
|
+
|
|
33
|
+
# env files (can opt-in for committing if needed)
|
|
34
|
+
.env*
|
|
35
|
+
|
|
36
|
+
# vercel
|
|
37
|
+
.vercel
|
|
38
|
+
|
|
39
|
+
# typescript
|
|
40
|
+
*.tsbuildinfo
|
|
41
|
+
next-env.d.ts
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { BCHConnectProvider, createConfig, CreatedConfig } from "bch-connect";
|
|
6
|
+
|
|
7
|
+
export function BCHConnectWrapper({ children }: { children: ReactNode }) {
|
|
8
|
+
const [config, setConfig] = useState<CreatedConfig | null>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (config) return;
|
|
12
|
+
const network =
|
|
13
|
+
process.env.NEXT_PUBLIC_BCH_NETWORK === "testnet" ? "testnet" : "mainnet";
|
|
14
|
+
|
|
15
|
+
const projectId = process.env.NEXT_PUBLIC_REOWN_PROJECT_ID || "";
|
|
16
|
+
|
|
17
|
+
const cfg = createConfig({
|
|
18
|
+
projectId,
|
|
19
|
+
network,
|
|
20
|
+
metadata: {
|
|
21
|
+
name: "BCH Connect Starter",
|
|
22
|
+
description:
|
|
23
|
+
"You can change this metadata in the app/BCHConnectWrapper.tsx file.",
|
|
24
|
+
url: "http://localhost:3000",
|
|
25
|
+
icons: ["http://localhost:3000/bch.svg"],
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
setConfig(cfg);
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
if (!config) return null;
|
|
33
|
+
|
|
34
|
+
return <BCHConnectProvider config={config}>{children}</BCHConnectProvider>;
|
|
35
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
9
|
+
line-height: 1.5;
|
|
10
|
+
font-weight: 400;
|
|
11
|
+
|
|
12
|
+
color-scheme: light dark;
|
|
13
|
+
color: rgba(255, 255, 255, 0.87);
|
|
14
|
+
background-color: #242424;
|
|
15
|
+
|
|
16
|
+
font-synthesis: none;
|
|
17
|
+
text-rendering: optimizeLegibility;
|
|
18
|
+
-webkit-font-smoothing: antialiased;
|
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
a {
|
|
23
|
+
font-weight: 500;
|
|
24
|
+
color: #646cff;
|
|
25
|
+
text-decoration: inherit;
|
|
26
|
+
}
|
|
27
|
+
a:hover {
|
|
28
|
+
color: #535bf2;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
body {
|
|
32
|
+
margin: 0;
|
|
33
|
+
display: flex;
|
|
34
|
+
place-items: center;
|
|
35
|
+
min-width: 320px;
|
|
36
|
+
min-height: 100vh;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
h1 {
|
|
40
|
+
font-size: 3.2em;
|
|
41
|
+
line-height: 1.1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.container {
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
button {
|
|
52
|
+
border-radius: 8px;
|
|
53
|
+
border: 1px solid transparent;
|
|
54
|
+
padding: 0.6em 1.2em;
|
|
55
|
+
font-size: 1em;
|
|
56
|
+
font-weight: 500;
|
|
57
|
+
font-family: inherit;
|
|
58
|
+
background-color: #1a1a1a;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
transition: border-color 0.25s;
|
|
61
|
+
}
|
|
62
|
+
button:hover {
|
|
63
|
+
border-color: #646cff;
|
|
64
|
+
}
|
|
65
|
+
button:focus,
|
|
66
|
+
button:focus-visible {
|
|
67
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (prefers-color-scheme: light) {
|
|
71
|
+
:root {
|
|
72
|
+
color: #213547;
|
|
73
|
+
background-color: #ffffff;
|
|
74
|
+
}
|
|
75
|
+
a:hover {
|
|
76
|
+
color: #747bff;
|
|
77
|
+
}
|
|
78
|
+
button {
|
|
79
|
+
background-color: #f9f9f9;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#root {
|
|
84
|
+
max-width: 1280px;
|
|
85
|
+
margin: 0 auto;
|
|
86
|
+
padding: 2rem;
|
|
87
|
+
text-align: center;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.title {
|
|
91
|
+
font-size: 2.5rem;
|
|
92
|
+
line-height: 1.1;
|
|
93
|
+
margin-top: 0.25rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.brand-logos {
|
|
97
|
+
display: flex;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 0.25rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.brand-logos .logo {
|
|
104
|
+
width: 7.5rem;
|
|
105
|
+
height: auto;
|
|
106
|
+
padding: 1.1rem;
|
|
107
|
+
will-change: filter;
|
|
108
|
+
transition: filter 300ms;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.brand-logos .logo:hover {
|
|
112
|
+
filter: drop-shadow(0 0 2em #ffffffac);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.brand-logos .logo.react:hover {
|
|
116
|
+
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.brand-logos .logo.bch:hover {
|
|
120
|
+
filter: drop-shadow(0 0 2em #2ecc71aa);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@keyframes logo-spin {
|
|
124
|
+
from {
|
|
125
|
+
transform: rotate(0deg);
|
|
126
|
+
}
|
|
127
|
+
to {
|
|
128
|
+
transform: rotate(360deg);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
133
|
+
a:nth-of-type(2) .logo {
|
|
134
|
+
animation: logo-spin infinite 20s linear;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.card {
|
|
139
|
+
padding: 2em;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.bchc-card {
|
|
143
|
+
display: grid;
|
|
144
|
+
gap: 0.9rem;
|
|
145
|
+
justify-items: center;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.bchc-primary {
|
|
149
|
+
min-width: 250px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.bchc-actions {
|
|
153
|
+
display: flex;
|
|
154
|
+
gap: 0.75rem;
|
|
155
|
+
flex-wrap: wrap;
|
|
156
|
+
justify-content: center;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.bchc-actions > button {
|
|
160
|
+
min-width: 250px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.bchc-status {
|
|
164
|
+
display: inline-flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 0.6rem;
|
|
167
|
+
padding: 0.35rem 0.7rem;
|
|
168
|
+
border-radius: 999px;
|
|
169
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
170
|
+
background: rgba(255, 255, 255, 0.04);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.bchc-dot {
|
|
174
|
+
width: 10px;
|
|
175
|
+
height: 10px;
|
|
176
|
+
border-radius: 50%;
|
|
177
|
+
background: #888;
|
|
178
|
+
display: inline-block;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.bchc-status[data-connected="true"] .bchc-dot {
|
|
182
|
+
background: #2ecc71;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.bchc-statusText {
|
|
186
|
+
font-size: 0.95rem;
|
|
187
|
+
opacity: 0.9;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.bchc-panel {
|
|
191
|
+
width: min(680px, 92vw);
|
|
192
|
+
text-align: left;
|
|
193
|
+
padding: 0.75rem;
|
|
194
|
+
border-radius: 12px;
|
|
195
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
196
|
+
background: rgba(255, 255, 255, 0.04);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.bchc-panel--error {
|
|
200
|
+
border-color: rgba(255, 255, 255, 0.14);
|
|
201
|
+
background: rgba(255, 80, 80, 0.08);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.bchc-panelTitle {
|
|
205
|
+
font-weight: 600;
|
|
206
|
+
margin-bottom: 6px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.bchc-panelBody {
|
|
210
|
+
opacity: 0.9;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.bchc-code {
|
|
214
|
+
word-break: break-word;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.bchc-footer {
|
|
218
|
+
margin: 0.15rem 0 0;
|
|
219
|
+
opacity: 0.75;
|
|
220
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
import { BCHConnectWrapper } from "./BCHConnectWrapper";
|
|
5
|
+
|
|
6
|
+
const geistSans = Geist({
|
|
7
|
+
variable: "--font-geist-sans",
|
|
8
|
+
subsets: ["latin"],
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const geistMono = Geist_Mono({
|
|
12
|
+
variable: "--font-geist-mono",
|
|
13
|
+
subsets: ["latin"],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const metadata: Metadata = {
|
|
17
|
+
title: "BCH Connect Starter",
|
|
18
|
+
description: "BCH Connect starter powered by Next.js",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function RootLayout({
|
|
22
|
+
children,
|
|
23
|
+
}: Readonly<{
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}>) {
|
|
26
|
+
return (
|
|
27
|
+
<html lang="en">
|
|
28
|
+
<body className={`${geistSans.variable} ${geistMono.variable}`}>
|
|
29
|
+
<BCHConnectWrapper>{children}</BCHConnectWrapper>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// REMOVE ALL THIS STUFF TO START BUILDING YOUR DAPP
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import Image from "next/image";
|
|
5
|
+
import { useSignMessage, useWallet } from "bch-connect";
|
|
6
|
+
|
|
7
|
+
function shortAddress(address: string): string {
|
|
8
|
+
const addr = address.replace(/^bitcoincash:/, "");
|
|
9
|
+
if (addr.length <= 18) return addr;
|
|
10
|
+
return `${addr.slice(0, 8)}…${addr.slice(-8)}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default function Home() {
|
|
14
|
+
const {
|
|
15
|
+
connect,
|
|
16
|
+
disconnect,
|
|
17
|
+
isConnected,
|
|
18
|
+
address,
|
|
19
|
+
isError,
|
|
20
|
+
connectError,
|
|
21
|
+
disconnectError,
|
|
22
|
+
addressError,
|
|
23
|
+
tokenAddressError,
|
|
24
|
+
} = useWallet();
|
|
25
|
+
|
|
26
|
+
const { signMessage } = useSignMessage();
|
|
27
|
+
|
|
28
|
+
const [signature, setSignature] = useState<string | null>(null);
|
|
29
|
+
const [isSigning, setIsSigning] = useState(false);
|
|
30
|
+
const [signError, setSignError] = useState<string | null>(null);
|
|
31
|
+
|
|
32
|
+
const statusText =
|
|
33
|
+
isConnected && address ? shortAddress(address) : "Not connected";
|
|
34
|
+
|
|
35
|
+
const walletError =
|
|
36
|
+
connectError?.message ??
|
|
37
|
+
disconnectError?.message ??
|
|
38
|
+
addressError?.message ??
|
|
39
|
+
tokenAddressError?.message;
|
|
40
|
+
|
|
41
|
+
function handleConnect() {
|
|
42
|
+
setSignError(null);
|
|
43
|
+
setSignature(null);
|
|
44
|
+
void connect();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function handleDisconnect() {
|
|
48
|
+
setSignError(null);
|
|
49
|
+
setSignature(null);
|
|
50
|
+
void disconnect();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function handleSignMessage() {
|
|
54
|
+
setIsSigning(true);
|
|
55
|
+
setSignError(null);
|
|
56
|
+
setSignature(null);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const sig = await signMessage({
|
|
60
|
+
message: "Bitcoin is cash!",
|
|
61
|
+
userPrompt: "Sign demo message",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!sig) throw new Error("No signature returned.");
|
|
65
|
+
setSignature(sig);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
const details = e instanceof Error ? e.message : JSON.stringify(e);
|
|
68
|
+
setSignError(`Failed to sign: ${details}`);
|
|
69
|
+
} finally {
|
|
70
|
+
setIsSigning(false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div className="container">
|
|
76
|
+
<div className="brand-logos">
|
|
77
|
+
<a href="https://nextjs.org" target="_blank" rel="noreferrer">
|
|
78
|
+
<Image
|
|
79
|
+
className="logo"
|
|
80
|
+
src="/next.svg"
|
|
81
|
+
alt="Next.js logo"
|
|
82
|
+
width={96}
|
|
83
|
+
height={20}
|
|
84
|
+
priority
|
|
85
|
+
/>
|
|
86
|
+
</a>
|
|
87
|
+
|
|
88
|
+
<a href="https://react.dev" target="_blank" rel="noreferrer">
|
|
89
|
+
<Image
|
|
90
|
+
className="logo react"
|
|
91
|
+
src="/react.svg"
|
|
92
|
+
alt="React logo"
|
|
93
|
+
width={56}
|
|
94
|
+
height={56}
|
|
95
|
+
priority
|
|
96
|
+
/>
|
|
97
|
+
</a>
|
|
98
|
+
|
|
99
|
+
<a href="https://bchconnect.dev" target="_blank" rel="noreferrer">
|
|
100
|
+
<Image
|
|
101
|
+
className="logo bch"
|
|
102
|
+
src="/bch.svg"
|
|
103
|
+
alt="BCH Connect logo"
|
|
104
|
+
width={56}
|
|
105
|
+
height={56}
|
|
106
|
+
priority
|
|
107
|
+
/>
|
|
108
|
+
</a>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<h1 className="title">BCH Connect Starter</h1>
|
|
112
|
+
|
|
113
|
+
<div className="card">
|
|
114
|
+
<div className="bchc-card">
|
|
115
|
+
{!isConnected ? (
|
|
116
|
+
<button
|
|
117
|
+
className="bchc-primary"
|
|
118
|
+
onClick={handleConnect}
|
|
119
|
+
disabled={isSigning}
|
|
120
|
+
>
|
|
121
|
+
Connect wallet
|
|
122
|
+
</button>
|
|
123
|
+
) : (
|
|
124
|
+
<div className="bchc-actions">
|
|
125
|
+
<button onClick={handleSignMessage} disabled={isSigning}>
|
|
126
|
+
{isSigning ? "Sign in your wallet…" : "Sign a message"}
|
|
127
|
+
</button>
|
|
128
|
+
|
|
129
|
+
<button onClick={handleDisconnect} disabled={isSigning}>
|
|
130
|
+
Disconnect
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
<div
|
|
136
|
+
className="bchc-status"
|
|
137
|
+
data-connected={isConnected ? "true" : "false"}
|
|
138
|
+
>
|
|
139
|
+
<span className="bchc-dot" aria-hidden="true" />
|
|
140
|
+
<span className="bchc-statusText">{statusText}</span>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{signError ? (
|
|
144
|
+
<div className="bchc-panel bchc-panel--error">
|
|
145
|
+
<div className="bchc-panelTitle">Error</div>
|
|
146
|
+
<div className="bchc-panelBody">{signError}</div>
|
|
147
|
+
</div>
|
|
148
|
+
) : null}
|
|
149
|
+
|
|
150
|
+
{isError && walletError ? (
|
|
151
|
+
<div className="bchc-panel bchc-panel--error">
|
|
152
|
+
<div className="bchc-panelTitle">Wallet error</div>
|
|
153
|
+
<div className="bchc-panelBody">{walletError}</div>
|
|
154
|
+
</div>
|
|
155
|
+
) : null}
|
|
156
|
+
|
|
157
|
+
{signature ? (
|
|
158
|
+
<div className="bchc-panel">
|
|
159
|
+
<div className="bchc-panelTitle">Message signature</div>
|
|
160
|
+
<code className="bchc-code">{signature}</code>
|
|
161
|
+
</div>
|
|
162
|
+
) : null}
|
|
163
|
+
|
|
164
|
+
<p className="bchc-footer">
|
|
165
|
+
Edit <code>app/page.tsx</code>.{" "}
|
|
166
|
+
<a href="https://bchconnect.dev" target="_blank" rel="noreferrer">
|
|
167
|
+
BCH Connect Docs
|
|
168
|
+
</a>
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nextjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"bch-connect": "^0.2.0",
|
|
12
|
+
"next": "16.1.1",
|
|
13
|
+
"react": "19.2.3",
|
|
14
|
+
"react-dom": "19.2.3"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^20",
|
|
18
|
+
"@types/react": "^19",
|
|
19
|
+
"@types/react-dom": "^19",
|
|
20
|
+
"babel-plugin-react-compiler": "1.0.0",
|
|
21
|
+
"typescript": "^5"
|
|
22
|
+
},
|
|
23
|
+
"ignoreScripts": [
|
|
24
|
+
"sharp",
|
|
25
|
+
"unrs-resolver"
|
|
26
|
+
],
|
|
27
|
+
"trustedDependencies": [
|
|
28
|
+
"sharp",
|
|
29
|
+
"unrs-resolver"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- Generator: Adobe Illustrator 24.1.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
3
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
4
|
+
viewBox="0 0 788 788" style="enable-background:new 0 0 788 788;" xml:space="preserve">
|
|
5
|
+
<style type="text/css">
|
|
6
|
+
.st0{fill:#0AC18E;}
|
|
7
|
+
.st1{fill:#FFFFFF;}
|
|
8
|
+
</style>
|
|
9
|
+
<circle class="st0" cx="394" cy="394" r="394"/>
|
|
10
|
+
<path id="symbol_1_" class="st1" d="M516.9,261.7c-19.8-44.9-65.3-54.5-121-45.2L378,147.1l-42.2,10.9l17.6,69.2
|
|
11
|
+
c-11.1,2.8-22.5,5.2-33.8,8.4L302,166.8l-42.2,10.9l17.9,69.4c-9.1,2.6-85.2,22.1-85.2,22.1l11.6,45.2c0,0,31-8.7,30.7-8
|
|
12
|
+
c17.2-4.5,25.3,4.1,29.1,12.2l49.2,190.2c0.6,5.5-0.4,14.9-12.2,18.1c0.7,0.4-30.7,7.9-30.7,7.9l4.6,52.7c0,0,75.4-19.3,85.3-21.8
|
|
13
|
+
l18.1,70.2l42.2-10.9l-18.1-70.7c11.6-2.7,22.9-5.5,33.9-8.4l18,70.3l42.2-10.9l-18.1-70.1c65-15.8,110.9-56.8,101.5-119.5
|
|
14
|
+
c-6-37.8-47.3-68.8-81.6-72.3C519.3,324.7,530,297.4,516.9,261.7L516.9,261.7z M496.6,427.2c8.4,62.1-77.9,69.7-106.4,77.2
|
|
15
|
+
l-24.8-92.9C394,404,482.4,372.5,496.6,427.2z M444.6,300.7c8.9,55.2-64.9,61.6-88.7,67.7l-22.6-84.3
|
|
16
|
+
C357.2,278.2,426.5,249.6,444.6,300.7z"/>
|
|
17
|
+
</svg>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" data-testid="geist-icon" height="16" stroke-linejoin="round" style="color:currentColor" viewBox="0 0 16 16" width="16"><g clip-path="url(#clip0_53_108)">
|
|
2
|
+
<circle cx="8" cy="8" r="7.375" fill="black" stroke="var(--ds-gray-1000)" strokewidth="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M10.63 11V5" stroke="url(#paint0_linear_53_108vsxrmxu21)" strokewidth="1.25" stroke-miterlimit="1.41421"/>
|
|
4
|
+
<path fill-rule="evenodd" cliprule="evenodd" d="M5.995 5.00087V5H4.745V11H5.995V6.96798L12.3615 14.7076C12.712 14.4793 13.0434 14.2242 13.353 13.9453L5.99527 5.00065L5.995 5.00087Z" fill="url(#paint1_linear_53_108vsxrmxu21)"/>
|
|
5
|
+
</g>
|
|
6
|
+
<defs>
|
|
7
|
+
<linearGradient id="paint0_linear_53_108vsxrmxu21" x1="11.13" y1="5" x2="11.13" y2="11" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="white"/>
|
|
9
|
+
<stop offset="0.609375" stop-color="white" stop-opacity="0.57"/>
|
|
10
|
+
<stop offset="0.796875" stop-color="white" stop-opacity="0"/>
|
|
11
|
+
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<linearGradient id="paint1_linear_53_108vsxrmxu21" x1="9.9375" y1="9.0625" x2="13.5574" y2="13.3992" gradientUnits="userSpaceOnUse">
|
|
14
|
+
<stop stop-color="white"/>
|
|
15
|
+
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
|
16
|
+
</linearGradient>
|
|
17
|
+
<clipPath id="clip0_53_108">
|
|
18
|
+
<rect width="16" height="16" fill="red"/>
|
|
19
|
+
</clipPath>
|
|
20
|
+
</defs></svg>
|