├── .env
├── .gitignore
├── LICENSE.txt
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── prettier.config.js
├── public
├── favicon
│ ├── android-icon-144x144.png
│ ├── android-icon-192x192.png
│ ├── android-icon-36x36.png
│ ├── android-icon-48x48.png
│ ├── android-icon-72x72.png
│ ├── android-icon-96x96.png
│ ├── apple-icon-114x114.png
│ ├── apple-icon-120x120.png
│ ├── apple-icon-144x144.png
│ ├── apple-icon-152x152.png
│ ├── apple-icon-180x180.png
│ ├── apple-icon-57x57.png
│ ├── apple-icon-60x60.png
│ ├── apple-icon-72x72.png
│ ├── apple-icon-76x76.png
│ ├── apple-icon-precomposed.png
│ ├── apple-icon.png
│ ├── browserconfig.xml
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon-96x96.png
│ ├── favicon.ico
│ ├── manifest.json
│ ├── ms-icon-144x144.png
│ ├── ms-icon-150x150.png
│ ├── ms-icon-310x310.png
│ └── ms-icon-70x70.png
├── houdini
│ └── smooth-corners.js
├── icon-cycle.svg
├── icon-new.svg
├── index.html
├── og
│ └── og.png
└── robots.txt
├── src
├── App.tsx
├── components
│ ├── ContentEditable.tsx
│ └── PaperWallet.tsx
├── lib
│ ├── random.js
│ └── strings.ts
├── main.tsx
├── static
│ ├── icon-cycle.svg
│ ├── icon-edit-text.svg
│ ├── icon-help.svg
│ ├── icon-logo.png
│ ├── icon-logo.svg
│ ├── icon-new.svg
│ └── icon-print.svg
└── style
│ └── index.css
├── tailwind.config.js
└── tsconfig.json
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_VERSION=$npm_package_version
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /dist
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Limerence Labs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hello Wallet
2 |
3 | [Try it.](https://hello-wallet.vercel.app/)
4 |
5 | Most paper wallets look bad. But what if they looked good? Using the latest graphic design technology it is possible to make a better paper wallet.
6 |
7 | ## Development
8 |
9 | This is a `create-react-app` and Tailwind CSS codebase. Start with the following:
10 |
11 | ```bash
12 | pnpm install
13 | pnpm run start
14 | ```
15 |
16 | ### To Do
17 |
18 | - [ ] Mobile
19 | - [ ] Printing modal with reminder to check `more settings` -> `background graphics` and set margins to `none`.
20 | - [ ] Paper Wallet info, pros + cons
21 | - [ ] Date format selection
22 | - [ ] Write-in mnemonic option
23 | - [ ] Add Eth Icon
24 |
25 | ### Future Ideas
26 | - [ ] Multisig, shards
27 | - [ ] Wallet with password
28 | - [ ] HD Wallet backup key + child key derivation UI
29 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hello Wallet
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-wallet",
3 | "version": "0.2.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.4",
7 | "@testing-library/react": "^13.3.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "ethers": "^5.7.2",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-scripts": "5.0.1",
13 | "web-vitals": "^2.1.4"
14 | },
15 | "scripts": {
16 | "dev": "vite",
17 | "build": "vite build"
18 | },
19 | "browserslist": {
20 | "production": [
21 | ">0.2%",
22 | "not dead",
23 | "not op_mini all"
24 | ],
25 | "development": [
26 | "last 1 chrome version",
27 | "last 1 firefox version",
28 | "last 1 safari version"
29 | ]
30 | },
31 | "devDependencies": {
32 | "typescript": "^5.3.3",
33 | "vite": "^5.1.4"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'always',
3 | singleQuote: true,
4 | tabWidth: 2,
5 | semi: false,
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicon/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-192x192.png
--------------------------------------------------------------------------------
/public/favicon/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-36x36.png
--------------------------------------------------------------------------------
/public/favicon/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-48x48.png
--------------------------------------------------------------------------------
/public/favicon/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-72x72.png
--------------------------------------------------------------------------------
/public/favicon/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/android-icon-96x96.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-114x114.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-120x120.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-152x152.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-180x180.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-57x57.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-60x60.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-72x72.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-76x76.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/public/favicon/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/apple-icon.png
--------------------------------------------------------------------------------
/public/favicon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/favicon-96x96.png
--------------------------------------------------------------------------------
/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/public/favicon/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/public/favicon/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicon/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/ms-icon-150x150.png
--------------------------------------------------------------------------------
/public/favicon/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/ms-icon-310x310.png
--------------------------------------------------------------------------------
/public/favicon/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/favicon/ms-icon-70x70.png
--------------------------------------------------------------------------------
/public/houdini/smooth-corners.js:
--------------------------------------------------------------------------------
1 | registerPaint('smooth-corners', class {
2 | static get inputProperties() {
3 | return [
4 | '--border-radius',
5 | '--stroke-width',
6 | '--stroke-color'
7 | ]
8 | }
9 |
10 | paint(ctx, size, styleMap) {
11 |
12 | const lw = parseInt(
13 | styleMap.get('--stroke-width').toString()
14 | )
15 |
16 | ctx.lineWidth = lw
17 |
18 | ctx.strokeStyle = styleMap.get('--stroke-color').toString()
19 |
20 | const r = parseInt(
21 | styleMap.get('--border-radius').toString()
22 | )
23 |
24 | const w = size.width - lw
25 | const h = size.height - lw
26 |
27 | const x = 0 + lw / 2
28 | const y = 0 + lw / 2
29 |
30 | ctx.beginPath();
31 |
32 | ctx.moveTo(x + r, y)
33 | ctx.lineTo(x + w - r, y)
34 | ctx.quadraticCurveTo(
35 | x + w,
36 | y,
37 | x + w,
38 | y + r
39 | )
40 | ctx.lineTo(
41 | x + w,
42 | y + h - r
43 | )
44 | ctx.quadraticCurveTo(
45 | x + w,
46 | y + h,
47 | x + w - r,
48 | y + h
49 | )
50 | ctx.lineTo(x + r, y + h)
51 | ctx.quadraticCurveTo(
52 | x,
53 | y + h,
54 | x,
55 | y + h - r
56 | )
57 | ctx.lineTo(x, y + r)
58 | ctx.quadraticCurveTo(x, y, x + r, y)
59 | ctx.closePath()
60 |
61 | ctx.stroke()
62 | }
63 | })
--------------------------------------------------------------------------------
/public/icon-cycle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/icon-new.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hello Wallet
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | You need to enable JavaScript to run this app.
48 |
49 |
52 |
53 |
--------------------------------------------------------------------------------
/public/og/og.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/public/og/og.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useMemo } from 'react'
2 | import * as Ethers from 'ethers'
3 | import { PaperWallet } from './components/PaperWallet'
4 | import { capitalizeFirstLetter } from './lib/strings'
5 | import { randomChoice } from './lib/random'
6 | import words from './lib/words.json'
7 | import pkg from '../package.json'
8 |
9 | const defaults = {
10 | title: '✏️ Hello Wallet',
11 | description:
12 | "✏️ Hello Wallet is a paper wallet you can edit in-browser. Save this wallet in a secure place only you control. Ready to print? Just press ⌘P.",
13 | }
14 |
15 | function generateWallet() {
16 | return Ethers.Wallet.createRandom()
17 | }
18 |
19 | function App() {
20 | const _wallet = useMemo(() => generateWallet(), [])
21 |
22 | const date = new Date().toLocaleDateString('en-US')
23 | const version = pkg.version
24 | const source = 'https://github.com/g-a-v-i-n/hello-wallet'
25 |
26 | const [wallet, setWallet] = useState(_wallet)
27 |
28 | return (
29 |
30 |
31 |
32 |
33 | {/* Shadow */}
34 |
35 | {/* Start printable area */}
36 |
44 |
setWallet(generateWallet())} className="absolute right-0 top-0 translate-x-8 -translate-y-8 bg-[#FFF] px-4 py-3 no-print text-[#373737] gap-x-2">
45 | Regenerate
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
About
54 |
Paper wallets are an offline method to secure cryptocurrencies, involving printing private keys and addresses on paper. They offer high security against online threats but must be carefully stored to avoid loss or damage.
55 |
While highly secure for long-term storage, using the funds requires transferring them to a digital wallet, introducing potential online risks. At one point, they were fairly common but were gradually replaced by somewhat better options like hardware wallets.
56 |
57 | Source Code
58 |
59 |
60 |
61 |
62 |
63 |
64 | )
65 | }
66 |
67 | export default App
68 |
--------------------------------------------------------------------------------
/src/components/ContentEditable.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | type ContentEditableProps = {
4 | as: 'div' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p'
5 | className?: string
6 | iconClassName?: string
7 | initialValue?: string
8 | }
9 |
10 | export const ContentEditable = (props: ContentEditableProps) => {
11 | const Component = props.as
12 |
13 | const internalProps = {
14 | contentEditable: true,
15 | role:"textbox",
16 | autoComplete: 'off',
17 | autoCorrect: 'off',
18 | autoCapitalize: 'off',
19 | className: props.className,
20 | suppressContentEditableWarning: true,
21 | // Removes rich text styles from clipboard text
22 | onPaste: (e: React.ClipboardEvent) => {
23 | // Cancel paste
24 | e.preventDefault()
25 | // Get text representation of clipboard
26 | const text = e.clipboardData?.getData('text/plain')
27 | // Insert text manually.
28 | document.execCommand('insertHTML', false, text)
29 | },
30 |
31 | }
32 |
33 | return (
34 |
35 | {props.initialValue}
36 |
37 | )
38 | }
39 |
40 | ContentEditable.defaultProps = {
41 | as: 'div',
42 | className: '',
43 | iconClassName: '',
44 | initialValue: '',
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/PaperWallet.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ContentEditable } from './ContentEditable'
3 | import { chunk } from '../lib/strings'
4 |
5 | export type PaperWalletProps = {
6 | address: string
7 | mnemonic: string
8 | title: string
9 | description: string
10 | date: string
11 | version?: string
12 | }
13 |
14 | export function PaperWallet(props: PaperWalletProps) {
15 | return (
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
Address
34 |
35 | Send and receive using this sharable public address.
36 |
37 |
38 |
{
40 | navigator.clipboard.writeText(props.address);
41 | }}
42 | className="no-print absolute bottom-0 right-0 flex px-3 py-2 items-center justify-center bg-white translate-x-6 translate-y-6">
43 | Copy
44 |
45 |
46 |
0x
47 |
48 | {
49 | /* @ts-ignore */
50 | chunk(props.address.slice(2), 4).map((chunk, i) => {
51 | return (
52 |
53 | {chunk}
54 |
55 | )
56 | })}
57 |
58 |
59 |
60 |
61 |
62 |
63 |
Seed Phrase
64 |
65 | Never share these secret words with anyone.
66 |
67 |
68 |
{
70 | navigator.clipboard.writeText(props.mnemonic);
71 | }}
72 | className="no-print absolute bottom-0 right-0 flex px-3 py-2 items-center justify-center bg-white translate-x-6 translate-y-6">
73 | Copy
74 |
75 |
76 | {props.mnemonic.split(' ').slice(0, 6).map((word, i) => {
77 | return (
78 |
79 | {i+1}
80 |
81 | {word}
82 |
83 |
84 | )
85 | })}
86 |
87 |
88 | {props.mnemonic.split(' ').slice(6, 12).map((word, i) => {
89 | return (
90 |
91 | {i+7}
92 |
93 | {word}
94 |
95 |
96 | )
97 | })}
98 |
99 |
100 |
101 |
102 |
103 |
104 | Notes
105 |
106 |
107 | A place for notes after this wallet is printed.
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
Ethereum
131 |
132 |
133 |
Hello Wallet Version
{' '}
134 |
135 | {props.version}
136 |
137 |
138 |
Generated on {props.date}
139 |
140 |
141 |
142 | )
143 | }
144 |
145 | PaperWallet.defaultProps = {
146 | address: '',
147 | mnemonic: '',
148 | emoji: '',
149 | title: '',
150 | description: '',
151 | date: '',
152 | version: '',
153 | }
154 |
--------------------------------------------------------------------------------
/src/lib/random.js:
--------------------------------------------------------------------------------
1 | const randomInt = (min, max) => {
2 | min = Math.ceil(min)
3 | max = Math.floor(max)
4 | return Math.floor(Math.random() * (max - min + 1)) + min
5 | }
6 |
7 | const randomChoice = (array) => {
8 | return array[randomInt(0, array.length - 1)]
9 | }
10 | export { randomInt, randomChoice }
11 |
--------------------------------------------------------------------------------
/src/lib/strings.ts:
--------------------------------------------------------------------------------
1 | export function capitalizeFirstLetter(str: string) {
2 | return str.charAt(0).toUpperCase() + str.slice(1)
3 | }
4 |
5 | export function chunk(str: string, size: number) {
6 | return str.match(new RegExp('.{1,' + size + '}', 'g'))
7 | }
8 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import "./style/index.css";
2 |
3 | import React from "react";
4 | import ReactDOM from "react-dom/client";
5 | import App from "./App";
6 |
7 | ReactDOM.createRoot(document.getElementById("root")!).render(
8 |
9 |
10 | ,
11 | );
12 |
--------------------------------------------------------------------------------
/src/static/icon-cycle.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/static/icon-edit-text.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/static/icon-help.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/static/icon-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/g-a-v-i-n/hello-wallet/6010ed00d1f5681fd014b1a015d65772b2d8780c/src/static/icon-logo.png
--------------------------------------------------------------------------------
/src/static/icon-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/static/icon-new.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/static/icon-print.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/style/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --shadow-color: 0deg 0% 74%;
7 | --shadow-elevation-low:
8 | 0.5px 0.5px 0.7px hsl(var(--shadow-color) / 0.34),
9 | 0.7px 0.7px 0.9px -1.9px hsl(var(--shadow-color) / 0.26),
10 | 1.7px 1.6px 2.2px -3.7px hsl(var(--shadow-color) / 0.19);
11 | --shadow-elevation-medium:
12 | 0.5px 0.5px 0.7px hsl(var(--shadow-color) / 0.28),
13 | 0.9px 0.9px 1.2px -0.9px hsl(var(--shadow-color) / 0.24),
14 | 1.9px 1.8px 2.5px -1.9px hsl(var(--shadow-color) / 0.21),
15 | 4.1px 4px 5.4px -2.8px hsl(var(--shadow-color) / 0.17),
16 | 8.4px 8.2px 11px -3.7px hsl(var(--shadow-color) / 0.13);
17 | --shadow-elevation-high:
18 | 0.5px 0.5px 0.7px hsl(var(--shadow-color) / 0.29),
19 | 1.2px 1.2px 1.6px -0.5px hsl(var(--shadow-color) / 0.27),
20 | 2.2px 2.1px 2.9px -0.9px hsl(var(--shadow-color) / 0.25),
21 | 3.7px 3.6px 4.8px -1.4px hsl(var(--shadow-color) / 0.23),
22 | 6.2px 6px 8.1px -1.9px hsl(var(--shadow-color) / 0.2),
23 | 10px 9.8px 13.1px -2.3px hsl(var(--shadow-color) / 0.18),
24 | 15.6px 15.2px 20.4px -2.8px hsl(var(--shadow-color) / 0.16),
25 | 23.3px 22.7px 30.5px -3.3px hsl(var(--shadow-color) / 0.14),
26 | 33.5px 32.7px 43.9px -3.7px hsl(var(--shadow-color) / 0.12);
27 | }
28 |
29 | @media print {
30 | .page-margin {
31 | margin: 0 !important;
32 | padding: 0 !important;
33 | }
34 |
35 | .no-print {
36 | display: none !important;
37 | height: 0 !important;
38 | padding: 0 !important;
39 | margin: 0 !important;
40 | }
41 |
42 | html,
43 | body {
44 | background-color: #fff !important;
45 | }
46 | }
47 |
48 | html,
49 | body {
50 | font-family: 'Inter', 'SF Pro Text', system-ui, sans-serif;
51 | @apply bg-[#FAFAFA];
52 | }
53 |
54 | a {
55 | text-decoration: underline;
56 | }
57 |
58 | .page-margin {
59 | margin-top: 8em;
60 | margin-bottom: 8em;
61 | }
62 |
63 | .page-size {
64 | /* */
65 | height: 11in;
66 | width: 8.6in;
67 | }
68 |
69 | .page-width {
70 | width: 8.5in;
71 | }
72 |
73 | .origin-top-center {
74 | transform-origin: top center;
75 | }
76 |
77 | .button-shadow {
78 |
79 |
80 | }
81 |
82 | button,
83 | .button {
84 | content: '';
85 | font-weight: 500;
86 | outline: 1px solid rgba(0,0,0,0.04);
87 | @apply flex shadow-elevation-medium items-center hover:scale-105 active:scale-100 transition-transform rounded-full;
88 | }
89 |
90 | .shadow-elevation-low {
91 | box-shadow: var(--shadow-elevation-low);
92 | }
93 |
94 | .shadow-elevation-medium {
95 | box-shadow: var(--shadow-elevation-medium);
96 | }
97 |
98 | .shadow-elevation-high {
99 | box-shadow: var(--shadow-elevation-high);
100 | }
101 |
102 |
103 | *[contenteditable='true'] {
104 | @apply relative border-transparent transition-colors -m-2 p-2 outline-none rounded-xl;
105 | }
106 |
107 | *[contenteditable='true']:focus {
108 | @apply border-transparent bg-[#EEF7FF];
109 | }
110 |
111 | *[contenteditable='true']::selection {
112 | @apply bg-gray-300;
113 | }
114 |
115 | *[contenteditable='true']::after {
116 | @apply absolute -left-8;
117 | }
118 |
119 |
120 | h1[contenteditable='true']::after {
121 | top: 14px;
122 | }
123 |
124 | p[contenteditable='true']::after {
125 | top: -1px;
126 | }
127 |
128 | p::selection, a::selection, h3::selection {
129 | color: #008cff !important;
130 | background-color: #CFE5FF !important;
131 | }
132 | /*
133 | .vr {
134 | content: '';
135 | border-color: black;
136 | border-style: solid;
137 | border-width: 1px;
138 | border-left: none;
139 | border-top: none;
140 | border-bottom: none;
141 | overflow-y: auto;
142 | display: flex;
143 | align-items: stretch;
144 | flex: 1;
145 | }
146 |
147 | .viewfinder {
148 | padding: 0.75em;
149 | position: relative;
150 | }
151 |
152 | .viewfinder:before,
153 | .viewfinder:after,
154 | .viewfinder > :first-child:before,
155 | .viewfinder > :first-child:after {
156 | position: absolute;
157 | content: ' ';
158 | width: 16px;
159 | height: 16px;
160 | border-color: black;
161 | border-style: solid;
162 | }
163 |
164 | .viewfinder:before {
165 | top: 0;
166 | left: 0;
167 | border-width: 1px 0 0 1px;
168 | border-radius: 10px 0 0 0;
169 | }
170 | .viewfinder:after {
171 | top: 0;
172 | right: 0;
173 | border-width: 1px 1px 0 0;
174 | border-radius: 0 10px 0 0;
175 | }
176 | .viewfinder > :first-child:before {
177 | bottom: 0;
178 | right: 0;
179 | border-width: 0 1px 1px 0;
180 | border-radius: 0 0 10px 0;
181 | }
182 | .viewfinder > :first-child:after {
183 | bottom: 0;
184 | left: 0;
185 | border-width: 0 0 1px 1px;
186 | border-radius: 0 0 0 10px;
187 | }
188 |
189 | @supports (mask-image: paint(smooth-corners)) {
190 | .superellipse-sm {
191 | border-radius: 0;
192 | stroke-width: 0;
193 | stroke: none;
194 | --border-radius: 8;
195 | --stroke-width: 1;
196 | --stroke-color: black;
197 | background-image: paint(smooth-corners);
198 | }
199 |
200 | .superellipse {
201 | border-radius: 0;
202 | stroke-width: 0;
203 | stroke: none;
204 | --border-radius: 14;
205 | --stroke-width: 1;
206 | --stroke-color: black;
207 | background-image: paint(smooth-corners);
208 | }
209 |
210 | .superellipse-lg {
211 | border-radius: 0;
212 | stroke-width: 0;
213 | stroke: none;
214 | --border-radius: 20;
215 | --stroke-width: 1;
216 | --stroke-color: black;
217 | background-image: paint(smooth-corners);
218 | }
219 | }
220 |
221 | .intro-transform {
222 | transform: translateY(0);
223 | } */
224 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: [
3 | "./src/**/*.{js,jsx,ts,tsx}",
4 | ],
5 | theme: {
6 | extend: {
7 | screens: {
8 | 'no-print': { 'raw': '(min-height: 800px)' },
9 | },
10 | },
11 | },
12 | plugins: [],
13 | }
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | },
18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------