From 3241775af439308a77a822e3caf98dcd17edbc83 Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Wed, 24 Jul 2024 02:03:50 -0600
Subject: [PATCH 01/12] build: :package: updates to support crowdnode
---
package-lock.json | 177 ++++++++++++++++++++++++++++++++++++++++------
package.json | 6 +-
2 files changed, 159 insertions(+), 24 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 096adb4..6f0e9ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,10 +11,11 @@
"dependencies": {
"@dashincubator/base58check": "^1.4.1",
"@dashincubator/ripemd160": "^3.0.0",
- "@dashincubator/secp256k1": "^1.7.1-5",
+ "@dashincubator/secp256k1": "dashhive/secp256k1.js#sync-with-upstream",
"@zxing/library": "^0.21.2",
+ "crowdnode": "dashhive/crowdnode.js#ref-dashtx",
"crypticstorage": "^0.0.2",
- "dashhd": "^3.3.3",
+ "dashhd": "dashhive/DashHD.js#ref-secp256k1-2.1.0-compat",
"dashkeys": "^1.1.4",
"dashphrase": "^1.4.0",
"dashsight": "dashhive/DashSight.js#feat/bulk-txs",
@@ -33,6 +34,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@dashincubator/base58check/-/base58check-1.4.1.tgz",
"integrity": "sha512-JSAO+viM3pVgM93XSBAUhLvK18BlRIsmYU4eGuyrj1lz3Xa1oplSel94oG0SI5d2qTxdy0NfGT3vEFbiKpfj5Q==",
+ "license": "SEE LICENSE IN LICENSE",
"bin": {
"base58check": "bin/base58check.js"
}
@@ -40,17 +42,25 @@
"node_modules/@dashincubator/ripemd160": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@dashincubator/ripemd160/-/ripemd160-3.0.0.tgz",
- "integrity": "sha512-EbdXcceP2mW76NchCKp8UYNbZgWkLuV4Mbi30G82xRED32ljJzXsKaaVdzU0oVo2fVzPRXF1GhSF6Lq9beTVvA=="
+ "integrity": "sha512-EbdXcceP2mW76NchCKp8UYNbZgWkLuV4Mbi30G82xRED32ljJzXsKaaVdzU0oVo2fVzPRXF1GhSF6Lq9beTVvA==",
+ "license": "MIT"
},
"node_modules/@dashincubator/secp256k1": {
- "version": "1.7.1-5",
- "resolved": "https://registry.npmjs.org/@dashincubator/secp256k1/-/secp256k1-1.7.1-5.tgz",
- "integrity": "sha512-3iA+RDZrJsRFPpWhlYkp3EdoFAlKjdqkNFiRwajMrzcpA/G/IBX0AnC1pwRLkTrM+tUowcyGrkJfT03U4ETZeg=="
+ "version": "2.1.0",
+ "resolved": "git+ssh://git@github.com/dashhive/secp256k1.js.git#d587c1a24ca7d5c47f7cb519ca70a54920da3245",
+ "license": "MIT"
+ },
+ "node_modules/@root/request": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@root/request/-/request-1.9.2.tgz",
+ "integrity": "sha512-wVaL9yVV9oDR9UNbPZa20qgY+4Ch6YN8JUkaE4el/uuS5dmhD8Lusm/ku8qJVNtmQA56XLzEDCRS6/vfpiHK2A==",
+ "license": "(MIT OR Apache-2.0)",
+ "optional": true
},
"node_modules/@types/node": {
- "version": "20.14.11",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
- "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
+ "version": "20.14.12",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz",
+ "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -76,17 +86,40 @@
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
"integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
+ "license": "(Unlicense OR Apache-2.0)",
"optional": true
},
+ "node_modules/crowdnode": {
+ "version": "1.8.0",
+ "resolved": "git+ssh://git@github.com/dashhive/crowdnode.js.git#2cfe200186a3d3ed7d1fb29edac0657825ddf7d0",
+ "license": "SEE LICENSE IN LICENSE",
+ "bin": {
+ "crowdnode": "bin/crowdnode.js"
+ },
+ "optionalDependencies": {
+ "@dashincubator/base58check": "^1.4.1",
+ "@dashincubator/ripemd160": "^3.0.0",
+ "@dashincubator/secp256k1": "dashhive/secp256k1.js#sync-with-upstream",
+ "@root/request": "^1.9.2",
+ "dashhd": "dashhive/DashHD.js#ref-secp256k1-2.1.0-compat",
+ "dashkeys": "^1.1.4",
+ "dashsight": "^1.6.1",
+ "dashtx": "^0.16.0",
+ "dotenv": "^16.4.5",
+ "qrcode-svg": "^1.1.0",
+ "tough-cookie": "^4.1.4",
+ "ws": "^8.18.0"
+ }
+ },
"node_modules/crypticstorage": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypticstorage/-/crypticstorage-0.0.2.tgz",
- "integrity": "sha512-PyiKq03ekJU1AwzYVchlm+LaUvDy939S1smmCD0fa60HLKVM0m6zEj4J/MXcm1BLrwdaZk9eRdJcau77nIOPAw=="
+ "integrity": "sha512-PyiKq03ekJU1AwzYVchlm+LaUvDy939S1smmCD0fa60HLKVM0m6zEj4J/MXcm1BLrwdaZk9eRdJcau77nIOPAw==",
+ "license": "MIT"
},
"node_modules/dashhd": {
"version": "3.3.3",
- "resolved": "https://registry.npmjs.org/dashhd/-/dashhd-3.3.3.tgz",
- "integrity": "sha512-sbhLV8EtmebnlIdx/d1hcbnxdfka/0rcLx+UO5y44kZdu5tyJ5ftBFbhhIb38vd+T+Xfcwpeo0z+0ZDznRkfaw==",
+ "resolved": "git+ssh://git@github.com/dashhive/DashHD.js.git#92cf91acf5633ed2ebed3b4f39d0d0f1d830679e",
"license": "SEE LICENSE IN LICENSE"
},
"node_modules/dashkeys": {
@@ -98,11 +131,13 @@
"node_modules/dashphrase": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/dashphrase/-/dashphrase-1.4.0.tgz",
- "integrity": "sha512-o+LdiPkiYmg07kXBE+2bbcJzBmeTQVPn1GS2XlQeo8lene+KknAprSyiYi5XtqV/QVgNjvzOV7qBst2MijSPAA=="
+ "integrity": "sha512-o+LdiPkiYmg07kXBE+2bbcJzBmeTQVPn1GS2XlQeo8lene+KknAprSyiYi5XtqV/QVgNjvzOV7qBst2MijSPAA==",
+ "license": "SEE LICENSE IN LICENSE"
},
"node_modules/dashsight": {
"version": "1.6.1",
"resolved": "git+ssh://git@github.com/dashhive/DashSight.js.git#11c1a740057ba646f89e8da2d85cb35dc67085f3",
+ "license": "SEE LICENSE IN LICENSE",
"dependencies": {
"dashtx": "^0.9.0-3"
},
@@ -121,6 +156,7 @@
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/dashtx/-/dashtx-0.9.0.tgz",
"integrity": "sha512-DDbH5vPChUpOrYMOoM+6g/Iy99KqG4nkJ6f8TphnGibzAY7mitjMgtFSc62YzbZdoPGYeSPm8N4jmz+Mbwm7Eg==",
+ "license": "SEE LICENSE IN LICENSE",
"bin": {
"dashtx-inspect": "bin/inspect.js"
}
@@ -156,36 +192,41 @@
}
},
"node_modules/dotenv": {
- "version": "16.3.1",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
- "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "license": "BSD-2-Clause",
"optional": true,
"engines": {
"node": ">=12"
},
"funding": {
- "url": "https://github.com/motdotla/dotenv?sponsor=1"
+ "url": "https://dotenvx.com"
}
},
"node_modules/html5-qrcode": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz",
- "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ=="
+ "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==",
+ "license": "Apache-2.0"
},
"node_modules/idb": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/idb/-/idb-8.0.0.tgz",
- "integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw=="
+ "integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==",
+ "license": "ISC"
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
- "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
},
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
+ "license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
@@ -194,22 +235,72 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
+ "license": "Apache-2.0",
"dependencies": {
"lie": "3.1.1"
}
},
+ "node_modules/psl": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/qrcode-svg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/qrcode-svg/-/qrcode-svg-1.1.0.tgz",
"integrity": "sha512-XyQCIXux1zEIA3NPb0AeR8UMYvXZzWEhgdBgBjH9gO7M48H9uoHzviNz8pXw3UzrAcxRRRn9gxHewAVK7bn9qw==",
+ "license": "MIT",
"bin": {
"qrcode-svg": "bin/qrcode-svg.js"
}
},
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+ "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/ts-custom-error": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
"integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==",
+ "license": "MIT",
"engines": {
"node": ">=14.0.0"
}
@@ -218,7 +309,51 @@
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index e44fb16..e904035 100644
--- a/package.json
+++ b/package.json
@@ -36,11 +36,11 @@
"dependencies": {
"@dashincubator/base58check": "^1.4.1",
"@dashincubator/ripemd160": "^3.0.0",
- "@dashincubator/secp256k1": "^1.7.1-5",
+ "@dashincubator/secp256k1": "dashhive/secp256k1.js#sync-with-upstream",
"@zxing/library": "^0.21.2",
- "crowdnode": "^1.8.0",
+ "crowdnode": "dashhive/crowdnode.js#ref-dashtx",
"crypticstorage": "^0.0.2",
- "dashhd": "^3.3.3",
+ "dashhd": "dashhive/DashHD.js#ref-secp256k1-2.1.0-compat",
"dashkeys": "^1.1.4",
"dashphrase": "^1.4.0",
"dashsight": "dashhive/DashSight.js#feat/bulk-txs",
From 34201939d9e547be231d722f4146c14269cf87ea Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Wed, 28 Aug 2024 10:43:20 -0600
Subject: [PATCH 02/12] feat: :lipstick: initial implementation of UI for
CrowdNode
---
src/components/crowdnode-card.js | 221 +++++++++++++
src/components/dialog.js | 119 ++++---
src/components/modal.js | 543 +++++++++++++++++++++++++++++++
src/components/svg-sprite.js | 4 +
src/helpers/constants.js | 12 +
src/helpers/lit.js | 18 +-
src/helpers/utils.js | 313 +++++++++++++++++-
src/imports.js | 8 +-
src/index.css | 64 +++-
src/main.js | 384 +++++++++++++++++++---
src/rigs/confirm-action.js | 34 +-
src/rigs/crowdnode-tx.js | 135 ++++++++
src/rigs/send-or-request.js | 81 +++--
src/rigs/show-error.js | 2 +-
src/secp.js | 11 +
src/styles/components.css | 46 +++
src/styles/dialog.css | 4 +-
src/styles/form.css | 25 +-
src/styles/motion.css | 12 +-
src/styles/progress.css | 29 +-
src/styles/theme.css | 13 +-
21 files changed, 1902 insertions(+), 176 deletions(-)
create mode 100644 src/components/crowdnode-card.js
create mode 100644 src/components/modal.js
create mode 100644 src/rigs/crowdnode-tx.js
create mode 100644 src/secp.js
diff --git a/src/components/crowdnode-card.js b/src/components/crowdnode-card.js
new file mode 100644
index 0000000..d0bceb2
--- /dev/null
+++ b/src/components/crowdnode-card.js
@@ -0,0 +1,221 @@
+import {
+ formDataEntries,
+ createSignal,
+} from '../helpers/utils.js'
+
+import {
+ lit as html,
+} from '../helpers/lit.js'
+
+export const CrowdNodeCard = (() => {
+ const initCfg = {
+ state: {},
+ slugs: {},
+ events: {},
+ elements: {},
+ markup: {},
+ }
+ const initialState = {
+ id: 'Card',
+ name: 'Card',
+ withdrawTxt: 'Withdraw',
+ withdrawAlt: 'Withdraw from Crowdnode',
+ depositTxt: 'Deposit',
+ depositAlt: `Deposit to Crowdnode`,
+ signupTxt: 'Signup',
+ signupAlt: `Signup for Crowdnode`,
+ placement: 'center',
+ rendered: null,
+ responsive: true,
+ }
+
+ const cn = function Crowdnode(
+ config = {}
+ ) {
+ config = {
+ ...initCfg,
+ ...config,
+ }
+
+ this.appElement = document.body
+
+ this.api = createSignal({})
+
+ this.state = {
+ ...initialState,
+ ...config.state,
+ }
+
+ this.slugs = {
+ form: this.state.name?.toLowerCase().replaceAll(' ', '_'),
+ ...config.slugs,
+ }
+
+ this.elements = {
+ ...config.elements,
+ }
+
+ this.markup = {}
+ this.markup.content = () => html`
+
+
+
+ ${!this.api.value?.acceptedToS && html`
+ Start earning interest by staking your Dash at CrowdNode
+ `}
+ ${this.api.value?.acceptedToS && html`
+
+ Balance: Ð ${this.api.value?.balance}
+
+ `}
+ ${this.api.value?.acceptedToS && html`
+
+ Earned: Ð ${this.api.value?.earned}
+
+ `}
+
+
+
+ ${!this.api.value?.acceptedToS && html`
+
+ ${this.state.signupTxt}
+
+ `}
+ ${this.api.value?.acceptedToS && html`
+
+ ${this.state.depositTxt}
+
+ `}
+ ${this.api.value?.acceptedToS && this.api.value?.balance > 0 && html`
+
+ ${this.state.withdrawTxt}
+
+ `}
+
+ `
+ this.markup = {
+ ...this.markup,
+ ...config.markup,
+ }
+
+ this.events = {
+ submit: event => {
+ event.preventDefault()
+ event.stopPropagation()
+
+ this.elements.form?.removeEventListener('submit', this.events.submit)
+
+ let fde = formDataEntries(event)
+
+ console.log(
+ `${this.slugs.form} submit`,
+ {event, fde},
+ )
+ },
+ ...config.events,
+ }
+
+ const $d = document
+
+ const form = $d.createElement('form')
+
+ this.elements.form = form
+
+ form.name = `${this.slugs.form}`
+ form.classList.add('flex', 'col', 'card')
+ form.innerHTML = this.markup.content()
+
+ this.api.on((apiChange) => {
+ console.log('CN Card API Change', apiChange)
+ this.render?.({})
+ })
+
+ /**
+ * Update the config of the CN Card
+ * @function
+ */
+ this.updateConfig = (config = {}) => {
+ console.log('CN Card updateConfig TOP', config)
+
+ for (let param in config) {
+ this[param] = {
+ ...this[param],
+ ...(config[param] || {}),
+ }
+ }
+
+ console.log('CN Card updateConfig BOT', this)
+ }
+
+ /**
+ * Trigger the rendering of the CN Card
+ * @function
+ */
+ this.render = ({
+ cfg = {},
+ position = 'afterend',
+ el = this.appElement,
+ }) => {
+ console.log('crowdnode render', this)
+
+ this.elements.form?.removeEventListener?.(
+ 'submit',
+ this.events.submit,
+ )
+
+ if (el !== this.appElement) {
+ this.appElement = el
+ }
+
+ this.updateConfig(cfg)
+
+ this.elements.form.name = this.slugs.form
+ this.elements.form.innerHTML = this.markup.content()
+
+ this.elements.form.addEventListener(
+ 'submit',
+ this.events.submit,
+ )
+
+ console.log('CARD RENDER', this, cfg)
+
+ if (!this.state.rendered) {
+ el.insertAdjacentElement(position, this.elements.form)
+ this.state.rendered = this.elements.form
+ }
+
+ this.events?.render?.(this)
+ }
+
+ return this
+ }
+
+ return cn
+})();
+
+export default CrowdNodeCard
diff --git a/src/components/dialog.js b/src/components/dialog.js
index b133a09..4551c39 100644
--- a/src/components/dialog.js
+++ b/src/components/dialog.js
@@ -4,6 +4,10 @@ import {
envoy,
} from '../helpers/utils.js'
+import {
+ DIALOG_STATUS,
+} from '../helpers/constants.js'
+
let modal = envoy(
{
rendered: {},
@@ -26,7 +30,8 @@ const initialState = {
rendered: null,
responsive: true,
delay: 500,
- async render () {},
+ status: DIALOG_STATUS.NOT_LOADING,
+ async render () { return this },
addListener () {},
addListeners () {},
removeAllListeners (targets) {},
@@ -210,6 +215,9 @@ const initialState = {
// event.target === state.elements.dialog,
// state.elements.dialog.returnValue
// )
+ state.status = DIALOG_STATUS.NOT_LOADING
+ state.elements.progress?.remove()
+ state.elements.progress = null
if (state.elements.dialog.returnValue !== 'cancel') {
resolve(state.elements.dialog.returnValue)
@@ -298,30 +306,30 @@ export async function setupDialog(
.replaceAll(/[^a-zA-Z _]/g, '')
.replaceAll(' ', '_')
- const dialog = document.createElement('dialog')
- const form = document.createElement('form')
- const progress = document.createElement('progress')
+ const dialogElement = document.createElement('dialog')
+ const formElement = document.createElement('form')
+ const progressElement = document.createElement('progress')
- state.elements.dialog = dialog
- state.elements.form = form
- state.elements.progress = progress
+ state.elements.dialog = dialogElement
+ state.elements.form = formElement
+ state.elements.progress = progressElement
- progress.classList.add('pending')
+ progressElement.classList.add('pending')
- dialog.innerHTML = ``
- dialog.id = state.slugs.dialog
+ dialogElement.innerHTML = ``
+ dialogElement.id = state.slugs.dialog
if (state.responsive) {
- dialog.classList.add('responsive')
+ dialogElement.classList.add('responsive')
}
- dialog.classList.add(state.placement)
+ dialogElement.classList.add(...(state.placement.split(' ')))
- form.name = `${state.slugs.form}`
- form.method = 'dialog'
- form.innerHTML = await state.content(state)
+ formElement.name = `${state.slugs.form}`
+ formElement.method = 'dialog'
+ formElement.innerHTML = await state.content(state)
- dialog.insertAdjacentElement(
+ dialogElement.insertAdjacentElement(
'afterbegin',
- form
+ formElement
)
function addListener(
@@ -340,74 +348,74 @@ export async function setupDialog(
) {
if (resolve && reject) {
addListener(
- dialog,
+ dialogElement,
'close',
state.events.handleClose(state, resolve, reject),
)
addListener(
- dialog,
+ dialogElement,
'click',
state.events.handleClick(state),
)
}
addListener(
- form,
+ formElement,
'blur',
state.events.handleBlur(state),
)
addListener(
- form,
+ formElement,
'focusout',
state.events.handleFocusOut(state),
)
addListener(
- form,
+ formElement,
'focusin',
state.events.handleFocusIn(state),
)
addListener(
- form,
+ formElement,
'change',
state.events.handleChange(state),
)
- // let updrop = form.querySelector('.updrop')
+ // let updrop = formElement.querySelector('.updrop')
// state.elements.updrop = updrop
// if (updrop) {
addListener(
- form,
+ formElement,
'drop',
state.events.handleDrop(state),
)
addListener(
- form,
+ formElement,
'dragover',
state.events.handleDragOver(state),
)
addListener(
- form,
+ formElement,
'dragend',
state.events.handleDragEnd(state),
)
addListener(
- form,
+ formElement,
'dragleave',
state.events.handleDragLeave(state),
)
// }
addListener(
- form,
+ formElement,
'input',
state.events.handleInput(state),
)
addListener(
- form,
+ formElement,
'reset',
state.events.handleReset(state),
)
addListener(
- form,
+ formElement,
'submit',
state.events.handleSubmit(state),
)
@@ -416,7 +424,7 @@ export async function setupDialog(
state.addListeners = addListeners
function removeAllListeners(
- targets = [dialog,form],
+ targets = [dialogElement,formElement],
) {
if (state.elements.updrop) {
targets.push(state.elements.updrop)
@@ -456,29 +464,56 @@ export async function setupDialog(
}
}
- dialog.id = state.slugs.dialog
- form.name = `${state.slugs.form}`
- form.innerHTML = await state.content(state)
+ dialogElement.id = state.slugs.dialog
+ formElement.name = `${state.slugs.form}`
+ formElement.innerHTML = await state.content(state)
// console.log('DIALOG RENDER', state, position, state.slugs.dialog, modal.rendered)
+ if (
+ state.status === DIALOG_STATUS.LOADING &&
+ state.elements.progress
+ ) {
+ state.elements.form.insertAdjacentElement(
+ 'beforebegin',
+ state.elements.progress,
+ )
+
+ // document.body.insertAdjacentHTML(
+ // 'afterbegin',
+ // ` `,
+ // )
+ }
+
+ if (
+ state.status === DIALOG_STATUS.SUCCESS ||
+ state.status === DIALOG_STATUS.ERROR
+ ) {
+ // document.getElementById('pageLoader')?.remove()
+ state.elements.progress?.remove()
+ }
+
if (!modal.rendered[state.slugs.dialog]) {
- el.insertAdjacentElement(position, dialog)
- modal.rendered[state.slugs.dialog] = dialog
+ el.insertAdjacentElement(position, dialogElement)
+ modal.rendered[state.slugs.dialog] = dialogElement
}
state.events.handleRender(state)
+
+ return state
}
state.render = render
return {
- element: dialog,
+ element: dialogElement,
+ state,
+ elements: state.elements,
show: (callback) => new Promise((resolve, reject) => {
removeAllListeners()
addListeners(resolve, reject)
- // console.log('dialog show', dialog)
- dialog.show()
+ // console.log('dialog show', dialogElement)
+ dialogElement.show()
state.events.handleShow?.(state)
callback?.()
}),
@@ -486,11 +521,11 @@ export async function setupDialog(
removeAllListeners()
addListeners(resolve, reject)
// console.log('dialog showModal', dialog)
- dialog.showModal()
+ dialogElement.showModal()
state.events.handleShow?.(state)
callback?.()
}),
- close: returnVal => dialog.close(returnVal),
+ close: returnVal => dialogElement.close(returnVal),
render,
}
}
diff --git a/src/components/modal.js b/src/components/modal.js
new file mode 100644
index 0000000..781e7a5
--- /dev/null
+++ b/src/components/modal.js
@@ -0,0 +1,543 @@
+import { lit as html } from '../helpers/lit.js'
+import {
+ formDataEntries,
+ createSignal,
+ effect,
+ toSlug,
+ addListener,
+ addListeners,
+ removeAllListeners,
+} from '../helpers/utils.js'
+
+import {
+ DIALOG_STATUS,
+} from '../helpers/constants.js'
+
+/**
+ * Create a new HTML Dialog
+ */
+export const DialogContructor = (() => {
+ const initCfg = {
+ state: {},
+ slugs: {},
+ events: {},
+ elements: {},
+ templates: {},
+ }
+ const initialState = {
+ id: 'Dialog',
+ name: 'Dialog',
+ submitTxt: 'Submit',
+ submitAlt: 'Submit Form',
+ cancelTxt: 'Cancel',
+ cancelAlt: `Cancel Form`,
+ closeTxt: 'X',
+ closeAlt: `Close`,
+ placement: 'center',
+ rendered: null,
+ responsive: true,
+ delay: 500,
+ status: DIALOG_STATUS.NOT_LOADING,
+ }
+
+ /**
+ * Create a new HTML Dialog
+ *
+ * @param {Object} config
+ */
+ const dl = function DialogModal(
+ config = {}
+ ) {
+ config = {
+ ...initCfg,
+ ...config,
+ }
+
+ this.eventHandlers = []
+
+ this.state = createSignal({
+ ...initialState,
+ ...config.state,
+ })
+
+ this.slugs = {
+ dialog: toSlug(this.state.value.name, this.state.value.id),
+ form: toSlug(this.state.value.id, this.state.value.name),
+ ...config.slugs,
+ }
+
+ this.appElement = document.body
+
+ this.elements = {
+ ...config.elements,
+ }
+
+ this.markup = {}
+
+ effect(() => {
+ this.markup.header = html`
+
+ ${this.state.value.name}
+ ${
+ this.state.value.closeTxt && html`${this.state.value.closeTxt} `
+ }
+
+ `
+ this.markup.footer = html`
+
+
+ ${this.state.value.cancelTxt}
+
+
+ ${this.state.value.submitTxt}
+
+
+ `
+ })
+
+ this.markup.fields = html`
+
+ Thing
+
+
+
+
Some instructions
+ `
+
+ this.markup.content = () => html`
+ ${this.markup.header}
+
+
+ ${this.markup.fields}
+
+
+
+
+ ${this.markup.footer}
+ `
+
+ this.markup = {
+ ...this.markup,
+ ...config.markup,
+ }
+
+ this.events = {
+ input: event => {
+ // let {
+ // // @ts-ignore
+ // name: fieldName, form,
+ // } = event?.target
+
+ // console.log('handle input', {
+ // fieldName,
+ // form,
+ // })
+
+ if (
+ event?.target?.validity?.patternMismatch &&
+ event?.target?.type !== 'checkbox'
+ ) {
+ event.preventDefault()
+ let label = event.target?.previousElementSibling?.textContent?.trim()
+ if (label) {
+ event.target.setCustomValidity(`Invalid ${label}`)
+ }
+ } else {
+ event.target.setCustomValidity('')
+ }
+ event.target.reportValidity()
+ },
+ change: event => {
+ // let {
+ // // @ts-ignore
+ // name: fieldName, form,
+ // } = event?.target
+
+ // console.log('handle change', {
+ // fieldName,
+ // form,
+ // })
+
+ if (
+ event?.target?.validity?.patternMismatch &&
+ event?.target?.type !== 'checkbox'
+ ) {
+ event.preventDefault()
+ let label = event.target?.previousElementSibling?.textContent?.trim()
+ if (label) {
+ event.target.setCustomValidity(`Invalid ${label}`)
+ }
+ } else {
+ event.target.setCustomValidity('')
+ }
+ event.target.reportValidity()
+ },
+ blur: event => {
+ // event.preventDefault()
+ // console.log(
+ // 'handle blur',
+ // event,
+ // )
+ },
+ focusout: event => {
+ // event.preventDefault()
+ // console.log(
+ // 'handle focus out',
+ // event,
+ // )
+ },
+ focusin: event => {
+ // event.preventDefault()
+ // console.log(
+ // 'handle focus in',
+ // event,
+ // )
+ },
+ drop: event => {
+ event.preventDefault()
+ },
+ dragover: event => {
+ event.preventDefault()
+ },
+ dragend: event => {
+ event.preventDefault()
+ },
+ dragleave: event => {
+ event.preventDefault()
+ },
+ render: (
+ state,
+ ) => {
+ // console.log(
+ // 'handle dialog render',
+ // state,
+ // )
+ },
+ show: (
+ state,
+ ) => {
+ // console.log(
+ // 'handle dialog show',
+ // state,
+ // )
+
+ // focus first input
+ this.elements.form.querySelector(
+ 'input'
+ )?.focus()
+ },
+ close: (
+ resolve = res=>{},
+ reject = res=>{},
+ ) => async event => {
+ event.preventDefault()
+ removeAllListeners.bind(this)
+
+ // console.log(
+ // 'handle dialog close',
+ // event,
+ // event.target === this.elements.dialog,
+ // this.elements.dialog.returnValue
+ // )
+ this.state.value.status = DIALOG_STATUS.NOT_LOADING
+ this.elements.dialog?.querySelector('progress')?.remove()
+
+ if (this.elements.dialog.returnValue !== 'cancel') {
+ resolve(this.elements.dialog.returnValue)
+ } else {
+ resolve('cancel')
+ }
+ // console.log(
+ // 'DIALOG handleClose',
+ // modal.rendered[this.slugs.dialog],
+ // )
+
+ setTimeout(t => {
+ // modal.rendered[this.slugs.dialog] = null
+ this.state.value.rendered = null
+ event?.target?.remove()
+ // console.log(
+ // 'DIALOG handleClose setTimeout',
+ // this.state.value.delay,
+ // // modal.rendered[this.slugs.dialog],
+ // modal.rendered,
+ // )
+ }, this.state.value.delay)
+ },
+ submit: event => {
+ event.preventDefault()
+
+ let fde = formDataEntries(event)
+
+ this.elements.dialog.returnValue = String(fde.intent)
+
+ // console.log(
+ // 'handleSubmit',
+ // [event],
+ // )
+
+ this.elements.dialog.close(String(fde.intent))
+ },
+ reset: event => {
+ event.preventDefault()
+ this.elements.form?.removeEventListener(
+ 'close',
+ this.events.reset
+ )
+ // console.log(
+ // 'handleReset',
+ // [event.target],
+ // )
+ this.elements.dialog.close('cancel')
+ },
+ click: event => {
+ if (event.target === this.elements.dialog) {
+ // console.log(
+ // 'handle dialog backdrop click',
+ // event,
+ // event.target === this.elements.dialog
+ // )
+ this.elements.dialog.close('cancel')
+ }
+ },
+ }
+
+ const dialogElement = document.createElement('dialog')
+ const formElement = document.createElement('form')
+ const progressElement = document.createElement('progress')
+
+ this.elements.dialog = dialogElement
+ this.elements.form = formElement
+ this.elements.progress = progressElement
+
+
+ this.element = this.elements.dialog
+
+ progressElement.classList.add('pending')
+
+ dialogElement.innerHTML = ``
+ dialogElement.id = this.slugs.dialog
+ if (this.state.value.responsive) {
+ dialogElement.classList.add('responsive')
+ }
+ dialogElement.classList.add(...(this.state.value.placement.split(' ')))
+
+ formElement.name = `${this.slugs.form}`
+ formElement.method = 'dialog'
+ // formElement.innerHTML = this.markup.content
+ formElement.innerHTML = this.markup.content()
+
+ dialogElement.insertAdjacentElement(
+ 'afterbegin',
+ formElement
+ )
+
+ /**
+ * Show the dialog
+ * @function
+ */
+ this.show = (callback, el = this.appElement) => new Promise((resolve, reject) => {
+ removeAllListeners.call(this)
+ addListeners.call(this, resolve, reject)
+ console.log('modal.js dialog show', this.elements.dialog)
+ // if (
+ // !this.state.value.rendered &&
+ // !el.contains(this.elements.dialog)
+ // ) {
+ this.render({
+ el,
+ // cfg: config,
+ position: 'afterend'
+ })
+ // }
+ this.elements.dialog.show()
+ this.events.show?.(this)
+ callback?.()
+ })
+
+ /**
+ * Show the Modal form of the dialog
+ * @function
+ */
+ this.showModal = (callback, el = this.appElement) => new Promise((resolve, reject) => {
+ removeAllListeners.call(this)
+ addListeners.call(this, resolve, reject)
+ console.log('modal.js dialog showModal', this, this.elements.dialog)
+ // if (
+ // !this.state.value.rendered &&
+ // !el.contains(this.elements.dialog)
+ // ) {
+ this.render({
+ el,
+ // cfg: config,
+ position: 'afterend'
+ })
+ // }
+ this.elements.dialog.showModal()
+ this.events.show?.(this)
+ callback?.()
+ })
+
+ /**
+ * Close the dialog
+ * @function
+ */
+ this.close = returnVal => this.elements.dialog.close(returnVal)
+
+ /**
+ * Update the config of the dialog
+ * @function
+ */
+ this.updateConfig = (config = {}) => {
+ console.log('Dialog updateConfig TOP', config)
+
+ for (let param in config) {
+ // if (param === 'markup') {
+ // this[param].value = {
+ // ...this[param].value,
+ // ...(config[param] || {}),
+ // }
+ // } else {
+ if ('value' in this[param]) {
+ this[param].value = {
+ ...this[param].value,
+ ...(config[param] || {}),
+ }
+ } else {
+ this[param] = {
+ ...this[param],
+ ...(config[param] || {}),
+ }
+ }
+ // }
+ }
+
+ console.log('Dialog updateConfig BOT', this)
+ }
+
+ /**
+ * Trigger the rendering of the dialog
+ * @function
+ */
+ this.render = ({
+ cfg = {},
+ position = 'afterend',
+ el = this.appElement,
+ }) => {
+ console.log('dialog render', this, dl)
+
+ // this.elements.form?.removeEventListener?.(
+ // 'submit',
+ // this.events.submit,
+ // )
+
+ if (el !== this.appElement) {
+ this.appElement = el
+ }
+
+ this.updateConfig(cfg)
+
+ console.log('DIALOG elements', this, this.elements)
+
+ this.elements.dialog.id = this.slugs.dialog
+ this.elements.form.name = this.slugs.form
+ // this.elements.form.innerHTML = this.markup.content
+ this.elements.form.innerHTML = this.markup.content()
+
+ // this.elements.form.addEventListener(
+ // 'submit',
+ // this.events.submit,
+ // )
+
+ console.log('DIALOG RENDER STATE', this.state.value, cfg)
+
+ console.log('DIALOG RENDER', position, this.slugs.dialog)
+
+ if (
+ this.state.value.status === DIALOG_STATUS.LOADING
+ ) {
+ this.elements.form.insertAdjacentElement(
+ 'beforebegin',
+ this.elements.progress,
+ )
+
+ // document.body.insertAdjacentHTML(
+ // 'afterbegin',
+ // ` `,
+ // )
+ }
+
+ if (
+ this.state.value.status === DIALOG_STATUS.SUCCESS ||
+ this.state.value.status === DIALOG_STATUS.ERROR
+ ) {
+ // document.getElementById('pageLoader')?.remove()
+ this.elements.dialog.querySelector('progress')?.remove()
+ }
+
+ if (!this.state.value.rendered) {
+ console.log('!this.state.rendered el', el, this.appElement, this.elements.dialog)
+ // @ts-ignore
+ el?.insertAdjacentElement(position, this.elements.dialog)
+ this.state.value.rendered = this.elements.dialog
+
+ this.elements.dialog.addEventListener(
+ 'close',
+ this.events.close
+ )
+ }
+
+ // console.log('DIALOG RENDER', state, position, state.slugs.dialog, modal.rendered)
+
+ this.events.render(this.state)
+
+ return this
+ }
+
+ // const updateSelf = (cfg, methods = []) => {
+ // for (let mthd of methods) {
+ // this[mthd] = {
+ // ...this[mthd],
+ // ...(cfg[mthd] || {}),
+ // }
+ // }
+ // }
+ // updateSelf(cfg, [
+ // 'state', 'slugs', 'events', 'elements', 'templates'
+ // ])
+
+ // state.render = render
+ }
+
+ return dl
+})();
+
+// export function Modal(config) {
+// let dialog = new DialogContructor(config)
+
+// console.log('Modal.js Dialog', dialog)
+
+// return dialog
+// }
+
+export default DialogContructor
diff --git a/src/components/svg-sprite.js b/src/components/svg-sprite.js
index 3fa2055..0c7184a 100644
--- a/src/components/svg-sprite.js
+++ b/src/components/svg-sprite.js
@@ -7,6 +7,10 @@ const initialState = {
+
+
+
+
diff --git a/src/helpers/constants.js b/src/helpers/constants.js
index 629a956..e85f271 100644
--- a/src/helpers/constants.js
+++ b/src/helpers/constants.js
@@ -142,3 +142,15 @@ export const USAGE = {
RECEIVE,
CHANGE,
}
+
+const NOT_LOADING = 0
+const LOADING = 1
+const SUCCESS = 2
+const ERROR = 3
+
+export const DIALOG_STATUS = {
+ NOT_LOADING,
+ LOADING,
+ SUCCESS,
+ ERROR
+}
\ No newline at end of file
diff --git a/src/helpers/lit.js b/src/helpers/lit.js
index f976e5a..fe7792f 100644
--- a/src/helpers/lit.js
+++ b/src/helpers/lit.js
@@ -1,8 +1,24 @@
/**
+ * Code Highlighting for String Literals.
+ *
+ * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#raw_strings MDN Reference}
+ *
+ * @example
+ * import { lit as html, lit as css } from './utils.js'
+ * let h = html`${example}
`
+ * let c = css`div > span { color: #bad; }`
+ *
+ * // falsey values now default to empty string
+ * let falsey = html`${doesNotExist && html`
`}
`
+
+ * // falsey === '
'
+ * // instead of
+ * // falsey === 'undefined
'
*
* @param {TemplateStringsArray} s
* @param {...any} v
*
* @returns {string}
*/
-export const lit = (s, ...v) => String.raw({ raw: s }, ...v)
+export const lit = (s, ...v) => String.raw({ raw: s }, ...(v.map(x => x || '')))
+// export const lit = (s, ...v) => String.raw({ raw: s }, ...v)
diff --git a/src/helpers/utils.js b/src/helpers/utils.js
index 493808f..f613de1 100644
--- a/src/helpers/utils.js
+++ b/src/helpers/utils.js
@@ -13,6 +13,10 @@ import {
SECONDS, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR,
} from './constants.js'
+let currentSignal;
+let globalDerivedValue;
+let eventHandlers = []
+
/**
*
* @param {String} [phraseOrXkey]
@@ -446,14 +450,14 @@ export function envoy(obj, ...initListeners) {
* document.querySelector("body").innerHTML = value;
* });
*
- * off(); // unsubscribe
+ * off();
*
* @param {Object} initialValue inital value
*/
export function createSignal(initialValue) {
let _value = initialValue;
let _last = _value;
- const subs = [];
+ let subs = [];
function pub() {
for (let s of subs) {
@@ -461,18 +465,186 @@ export function createSignal(initialValue) {
}
}
+ function unsub(fn) {
+ for (let i in subs) {
+ if (subs[i] === fn) {
+ subs[i] = 0;
+ // break;
+ }
+ }
+ }
+
+ function on(s) {
+ const i = subs.push(s)-1;
+ return () => { subs[i] = 0; };
+ }
+
+ function once(s) {
+ const i = subs.length
+
+ subs.push((_value, _last) => {
+ s && s(_value, _last);
+ subs[i] = 0;
+ });
+ }
+
return {
- get value() { return _value; },
+ get value() {
+ if (
+ currentSignal //&&
+ // currentSignal !== globalDerivedValue
+ ) {
+ console.log(
+ 'currentSignal === derived',
+ {currentSignal, derived, globalDerivedValue},
+ currentSignal === globalDerivedValue,
+ )
+ on(currentSignal)
+ }
+ return _value;
+ },
set value(v) {
_last = _value
_value = v;
pub();
},
- on: s => {
- const i = subs.push(s)-1;
- return () => { subs[i] = 0; };
+ on,
+ once,
+ unsub,
+ }
+}
+
+/**
+ * Use a reactive signal in hook fashion
+ *
+ * @example
+ * let [count, setCount, on] = useSignal(0)
+ * console.log(count()) // 0
+ * setCount(2)
+ * console.log(count()) // 2
+ *
+ * let off = on(value => {
+ * document.querySelector("body").innerHTML = value;
+ * });
+ *
+ * off()
+ *
+ * @param {Object} initialValue inital value
+*/
+export function useSignal(initialValue) {
+ let _value = initialValue;
+ let _last = _value;
+ let subs = [];
+
+ function pub() {
+ for (let s of subs) {
+ s && s(_value, _last);
+ }
+ }
+
+ function unsub(fn) {
+ for (let i in subs) {
+ if (subs[i] === fn) {
+ subs[i] = 0;
+ // break;
+ }
}
}
+
+ function getValue(v) {
+ if (
+ currentSignal //&&
+ // currentSignal !== globalDerivedValue
+ ) {
+ on(currentSignal)
+ }
+ return _value;
+ }
+
+ function setValue(v) {
+ _last = _value
+ _value = v;
+ pub();
+ }
+
+ function on(s) {
+ const i = subs.push(s)-1;
+ return () => { subs[i] = 0; };
+ }
+
+ function once(s) {
+ const i = subs.length
+
+ subs.push((_value, _last) => {
+ s && s(_value, _last);
+ subs[i] = 0;
+ });
+ }
+
+ return [
+ // _value,
+ getValue,
+ setValue,
+ on,
+ once,
+ unsub,
+ ]
+}
+
+/**
+ * {@link https://youtu.be/t18Kzj9S8-M?t=351 Understanding Signals}
+ *
+ * {@link https://youtu.be/1TSLEzNzGQM Learn Why JavaScript Frameworks Love Signals By Implementing Them}
+ *
+ * @example
+ * const [count, setCount] = useSignal(10)
+ * effect(() => console.log(count()))
+ * setCount(25)
+ *
+ * let letter = createSignal('a')
+ * effect(() => console.log(letter.value))
+ * letter.value = 'b'
+ *
+ * @param {Function} fn
+ */
+export function effect(fn) {
+ currentSignal = fn;
+
+ fn();
+
+ currentSignal = null;
+
+ return fn
+}
+
+/**
+ * {@link https://youtu.be/1TSLEzNzGQM Learn Why JavaScript Frameworks Love Signals By Implementing Them}
+ *
+ * @example
+ * let count = createSignal(10)
+ * let double = derived(() => count.value * 2)
+ *
+ * effect(
+ * () => console.log(
+ * count.value,
+ * double.value,
+ * )
+ * )
+ *
+ * count.value = 25
+ *
+ * @param {Function} fn
+ */
+export function derived(fn) {
+ const derived = createSignal()
+
+ globalDerivedValue = function derivedValue() {
+ derived.value = fn()
+ }
+
+ effect(globalDerivedValue)
+
+ return derived
}
export async function restate(
@@ -934,6 +1106,20 @@ export function nobounce(callback, delay = 300) {
}
}
+
+/**
+ * @example
+ * await forIt(500);
+ * nowDoThis()
+ *
+ * @param {number} [delay]
+*
+* @returns {Promise}
+*/
+export function forIt(delay) {
+ return new Promise(resolve => setTimeout(resolve, delay));
+}
+
export function timeago(ms, locale = TIMEAGO_LOCALE_EN) {
var ago = Math.floor(ms / 1000);
var part = 0;
@@ -1213,3 +1399,118 @@ export function getAddressIndexFromUsage(wallet, account, usageIdx) {
addressIndex,
}
}
+
+export function toSlug(...slugs) {
+ return slugs.join('_').toLowerCase()
+ .replaceAll(/[^a-zA-Z _]/g, '')
+ .replaceAll(' ', '_')
+}
+
+export function addListener(
+ node,
+ event,
+ handler,
+ capture = false,
+ handlers = this?.eventHandlers || eventHandlers,
+) {
+ console.log('addListener', this, { node, event, handler, capture })
+ handlers.push({ node, event, handler, capture })
+ node.addEventListener(event, handler, capture)
+}
+
+export function addListeners(
+ resolve,
+ reject,
+) {
+ if (resolve && reject) {
+ addListener(
+ this.elements.dialog,
+ 'close',
+ this.events.close(resolve, reject),
+ )
+
+ addListener(
+ this.elements.dialog,
+ 'click',
+ this.events.click,
+ )
+ }
+
+ addListener(
+ this.elements.form,
+ 'blur',
+ this.events.blur,
+ )
+ addListener(
+ this.elements.form,
+ 'focusout',
+ this.events.focusout,
+ )
+ addListener(
+ this.elements.form,
+ 'focusin',
+ this.events.focusin,
+ )
+ addListener(
+ this.elements.form,
+ 'change',
+ this.events.change,
+ )
+ // if (updrop) {
+ addListener(
+ this.elements.form,
+ 'drop',
+ this.events.drop,
+ )
+ addListener(
+ this.elements.form,
+ 'dragover',
+ this.events.dragover,
+ )
+ addListener(
+ this.elements.form,
+ 'dragend',
+ this.events.dragend,
+ )
+ addListener(
+ this.elements.form,
+ 'dragleave',
+ this.events.dragleave,
+ )
+ // }
+ addListener(
+ this.elements.form,
+ 'input',
+ this.events.input,
+ )
+ addListener(
+ this.elements.form,
+ 'reset',
+ this.events.reset,
+ )
+ addListener(
+ this.elements.form,
+ 'submit',
+ this.events.submit,
+ )
+}
+
+export function removeAllListeners(
+ targets = [
+ this?.elements.dialog,
+ this?.elements.form,
+ ],
+ handlers = this?.eventHandlers || eventHandlers,
+) {
+ if (this.elements.updrop) {
+ targets.push(this.elements.updrop)
+ }
+ handlers = handlers
+ .filter(({ node, event, handler, capture }) => {
+ if (targets.includes(node)) {
+ node.removeEventListener(event, handler, capture)
+ return false
+ }
+ return true
+ })
+}
diff --git a/src/imports.js b/src/imports.js
index 9057285..81fb104 100644
--- a/src/imports.js
+++ b/src/imports.js
@@ -11,6 +11,7 @@
*
* See https://github.com/jojobyte/browser-import-rabbit-hole
*/
+import './secp.js';
import '../node_modules/dashtx/dashtx.js';
import '../node_modules/dashkeys/dashkeys.js';
@@ -20,7 +21,7 @@ import '../node_modules/dashsight/dashsight.js';
import '../node_modules/dashsight/dashsocket.js';
import '../node_modules/@dashincubator/base58check/base58check.js';
import '../node_modules/@dashincubator/ripemd160/ripemd160.js';
-import '../node_modules/@dashincubator/secp256k1/secp256k1.js';
+// import '../node_modules/@dashincubator/secp256k1/secp256k1.js';
import '../node_modules/crypticstorage/cryptic.js';
import '../node_modules/dashwallet/dashwallet.js';
import '../node_modules/localforage/dist/localforage.js';
@@ -56,7 +57,10 @@ export let Base58Check = window?.Base58Check || globalThis?.Base58Check;
/** @type {RIPEMD160Types} */
export let RIPEMD160 = window?.RIPEMD160 || globalThis?.RIPEMD160;
/** @type {Secp256k1Types} */
-export let Secp256k1 = window?.nobleSecp256k1 || globalThis?.nobleSecp256k1;
+export let Secp256k1 = (
+ window?.nobleSecp256k1 || globalThis?.nobleSecp256k1 ||
+ window?.Secp256k1 || globalThis?.Secp256k1
+);
/** @type {CrypticTypes} */
export let Cryptic =
window?.Cryptic || globalThis?.Cryptic;
diff --git a/src/index.css b/src/index.css
index afa2fa0..11382a1 100644
--- a/src/index.css
+++ b/src/index.css
@@ -96,16 +96,35 @@ figure h4 {
font-size: 2rem;
}
-.mh-25 {
+.min-h-auto {
+ min-height: auto;
+}
+.min-h-0 {
+ min-height: 0;
+}
+.min-h-25 {
+ min-height: 25%;
+}
+.min-h-50 {
+ min-height: 50%;
+}
+.min-h-75 {
+ min-height: 75%;
+}
+.min-h-100 {
+ min-height: 100%;
+}
+
+.max-h-25 {
max-height: 25%;
}
-.mh-50 {
+.max-h-50 {
max-height: 50%;
}
-.mh-75 {
+.max-h-75 {
max-height: 75%;
}
-.mh-100 {
+.max-h-100 {
max-height: 100%;
}
@@ -167,9 +186,24 @@ figure h4 {
.jc-start {
justify-content: start;
}
+.jc-center {
+ justify-content: center;
+}
+.jc-right {
+ justify-content: right;
+}
.jc-end {
justify-content: end;
}
+.jc-around {
+ justify-content: space-around;
+}
+.jc-between {
+ justify-content: space-between;
+}
+.jc-evenly {
+ justify-content: space-evenly;
+}
.as-start {
align-self: start;
}
@@ -320,6 +354,28 @@ figure h4 {
font-size: 1.5rem;
}
+.p-0 {
+ padding: 0;
+}
+.p-1 {
+ padding: .25rem;
+}
+.p-2 {
+ padding: .75rem;
+}
+.p-3 {
+ padding: 1rem;
+}
+.p-4 {
+ padding: 1.5rem;
+}
+.p-5 {
+ padding: 2rem;
+}
+.p-6 {
+ padding: 2.5rem;
+}
+
.px-0 {
padding-left: 0;
padding-right: 0;
diff --git a/src/main.js b/src/main.js
index 3f06a08..f23ab8e 100644
--- a/src/main.js
+++ b/src/main.js
@@ -6,10 +6,16 @@ import {
getStoreData,
loadStoreObject,
formDataEntries,
+ // forIt,
+ // useSignal,
+ // createSignal,
+ // effect,
+ // derived,
} from './helpers/utils.js'
import {
DUFFS,
+ DIALOG_STATUS,
} from './helpers/constants.js'
import {
@@ -79,6 +85,8 @@ import pairQrRig from './rigs/pair-qr.js'
import txInfoRig from './rigs/tx-info.js'
import showErrorDialog from './rigs/show-error.js'
+import crowdnodeTransactionRig from './rigs/crowdnode-tx.js'
+
// app/data state
let accounts
let wallets
@@ -431,6 +439,40 @@ async function showNotification({
console.log('notification', {type, title, msg, sticky})
}
+async function showQrCode(state = {}) {
+ let initState = {
+ name: 'Share to receive funds',
+ submitTxt: `Edit Amount or Contact`,
+ submitAlt: `Change the currently selected contact`,
+ footer: state => html`
+
+
+ ${state.submitTxt}
+
+
+ `,
+ amount: 0,
+ wallet,
+ contacts: appState.contacts,
+ ...state,
+ }
+
+ let showRequestQRRender = await appDialogs.requestQr.render(
+ initState,
+ 'afterend',
+ )
+
+ let showRequestQR = await appDialogs.requestQr.showModal()
+
+ return showRequestQRRender
+}
+
async function main() {
appState.encryptionPassword = window.atob(
sessionStorage.encryptionPassword || ''
@@ -673,32 +715,9 @@ async function main() {
// }
// )
- await appDialogs.requestQr.render(
- {
- name: 'Share to receive funds',
- submitTxt: `Edit Amount or Contact`,
- submitAlt: `Change the currently selected contact`,
- footer: state => html`
-
-
- ${state.submitTxt}
-
-
- `,
- amount: 0,
- wallet,
- contacts: appState.contacts,
- },
- 'afterend',
- )
+ showQrCode()
- let showRequestQR = await appDialogs.requestQr.showModal()
+ // let showRequestQR = await appDialogs.requestQr.showModal()
}
} else {
await appDialogs.sendOrReceive.render({
@@ -766,6 +785,7 @@ async function main() {
res.push(await appTools.storedData?.decryptData?.(v) || v)
},
)
+ console.log('appState.contacts', appState.contacts)
await contactsList.render({
userInfo,
@@ -790,23 +810,301 @@ async function main() {
walletFunds,
})
})
+ import('./components/crowdnode-card.js')
+ .then(async ({ CrowdNodeCard }) => {
+ // let crowdnodeTransaction = crowdnodeTransactionRig
+ console.log(
+ 'crowdnodeTransactionRig',
+ crowdnodeTransactionRig,
+ crowdnodeTransactionRig.markup.fields,
+ )
+ // crowdnodeTransactionRig.markup.fields
+ let cfg = {
+ state: {
+ // name: '',
+ },
+ events: {
+ submit: async event => {
+ event.preventDefault()
+ event.stopPropagation()
- integrationsSection.insertAdjacentHTML('beforeend', html`
-
-
- Coming soon
- Earn interest with
-
-
-
- `)
+ // this.elements.form?.removeEventListener('submit', this.events.submit)
+
+ let fde = formDataEntries(event)
+
+ console.log(
+ `Crowdnode Card submit`,
+ {event, fde},
+ )
+
+ if (fde.intent === 'signup') {
+ let confAct = await appDialogs.confirmAction.render({
+ name: 'Signup for Crowdnode',
+ actionTxt: 'Signup',
+ actionAlt: 'Signup for Crowdnode',
+ action: '',
+ actionType: 'infoo',
+ placement: 'center auto-height',
+ // status: DIALOG_STATUS.LOADING,
+ acceptedToS: false,
+ submitIcon: () => ``,
+ alert: state => html`
+
+
+
+ I accept the CrowdNode Terms and Conditions
+
+ This process may take a while, please be patient.
+
+ `,
+ fields: () => html`
+
+
+ To stake your Dash and begin earning interest, read and accept the CrowdNode Terms and Conditions.
+ Funds are required to complete the signup process.
+
+
+ `,
+ callback: async (state, fde) => {
+ state.status = DIALOG_STATUS.LOADING
+
+ if (fde?.acceptToS === 'on') {
+ state.acceptedToS = true
+ }
+
+ let cbConfAct = await appDialogs.confirmAction.render(state)
+
+ console.log(
+ `confirm action`,
+ {state, fde, cbConfAct},
+ )
+
+ let cnFunding = await showQrCode({
+ name: 'CrowdNode Funding',
+ amount: 1.1,
+ status: DIALOG_STATUS.LOADING,
+ // wallet,
+ // contacts: appState.contacts,
+ // submitTxt: `Fund your wallet`,
+ // submitAlt: `Change the currently selected contact`,
+ generateNextAddress: state => {
+ // return html``
+ return html`
+ Send 1.1 Dash or more
+ to signup & fund your CrowdNode account.
+ `
+ },
+ footer: state => html`
+
+ `,
+ })
+
+ // await forIt(5000)
+
+ state.status = DIALOG_STATUS.SUCCESS
+
+ cbConfAct = await appDialogs.confirmAction.render(state)
+
+ console.log('CN Card Funding Callback', cnCard)
+
+ cnCard.api.value = {
+ acceptedToS: true,
+ balance: 1.234,
+ earned: 0.987,
+ }
+
+ cnCard.render({
+ cfg,
+ el: integrationsSection,
+ position: 'beforeend'
+ })
+
+ console.log(
+ `confirm action SUCCESS`,
+ {state, fde, cnFunding},
+ )
+
+ return { state, fde }
+ },
+ })
+
+ // let confAct = appDialogs.confirmAction.render({
+ // el: mainApp,
+ // cfg: {
+ // appElement: mainApp,
+ // state: {
+ // name: 'Signup for Crowdnode',
+ // actionTxt: 'Signup',
+ // actionAlt: 'Signup for Crowdnode',
+ // action: '',
+ // actionType: 'infoo',
+ // placement: 'center auto-height',
+ // // status: DIALOG_STATUS.LOADING,
+ // },
+ // markup: {
+ // submitIcon: ``,
+ // alert: html`
+ //
+ //
+ //
+ // I accept the CrowdNode Terms and Conditions
+ //
+ // This process may take a while, please be patient.
+ //
+ // `,
+ // fields: html`
+ //
+ //
+ // To stake your Dash and begin earning interest, read and accept the CrowdNode Terms and Conditions.
+ // Funds are required to complete the signup process.
+ //
+ //
+ // `,
+ // },
+ // callback: async (state, fde) => {
+ // state.status = DIALOG_STATUS.LOADING
+
+ // let cbConfAct = await appDialogs.confirmAction.render(state)
+
+ // console.log(
+ // `confirm action`,
+ // {state, fde, cbConfAct},
+ // )
+
+ // await forIt(5000)
+
+ // state.status = DIALOG_STATUS.SUCCESS
+
+ // console.log(
+ // `confirm action SUCCESS`,
+ // {state, fde},
+ // )
+
+ // return { state, fde }
+ // },
+ // },
+ // })
+
+ console.log('CN Card confAct Submit Event', cnCard)
+ console.log('confAct', confAct, appDialogs.confirmAction)
+
+ confAct?.elements?.form?.classList.add?.('min-h-auto')
+
+ appDialogs.confirmAction.showModal()
+ }
+
+ console.log(
+ `Crowdnode Card submit TX`,
+ fde.intent,
+ {event, fde},
+ )
+
+ if (fde.intent === 'deposit') {
+ appDialogs.sendOrReceive?.elements?.form?.classList.add?.('min-h-auto')
+ await appDialogs.sendOrReceive.render({
+ name: 'Deposit to CrowdNode',
+ cashSend: () => html``,
+ hideAddressee: true,
+ action: fde.intent,
+ wallet,
+ account: appState.account,
+ userInfo,
+ contacts: appState.contacts,
+ to: '@crowdnode',
+ })
+ appDialogs.sendOrReceive.showModal()
+ }
+ if (fde.intent === 'withdraw') {
+ crowdnodeTransactionRig.markup.fields = html`
+
+
+
+
+ Enter the percentage you wish to unstake.
+ `
+
+ let cnWithdraw = crowdnodeTransactionRig.render({
+ el: mainApp,
+ cfg: {
+ state: {
+ name: 'Withdraw from CrowdNode',
+ submitTxt: 'Withdraw',
+ submitAlt: 'Withdraw funds from CrowdNode',
+ cancelTxt: 'Cancel',
+ cancelAlt: `Cancel Withdraw`,
+ },
+ },
+ })
+ cnWithdraw?.elements?.form?.classList.add?.('min-h-auto')
+
+ console.log(
+ `Crowdnode Card TX`,
+ fde.intent,
+ {cnWithdraw},
+ )
+ crowdnodeTransactionRig.showModal()
+ // cnWithdraw.showModal()
+ }
+ }
+ },
+ }
+
+ let cnCard = new CrowdNodeCard(cfg)
+ console.log('CN Card Outer', cnCard)
+
+ // cfg.events.submit =
+
+ // cnCard.updateConfig(cfg)
+
+ cnCard.render({
+ cfg,
+ el: integrationsSection,
+ position: 'beforeend'
+ })
+ })
+
+
+ // integrationsSection.insertAdjacentHTML('beforeend', html`
+ //
+ //
+ // Coming soon
+ // Earn interest with
+ //
+ //
+ //
+ // `)
let txs = await getTxs(
appState,
@@ -895,7 +1193,7 @@ async function main() {
action: 'lock',
actionType: 'warn',
alert: state => html``,
- callback: () => {
+ callback: async () => {
sessionStorage.clear()
window.location.reload()
},
@@ -925,7 +1223,7 @@ async function main() {
This is an irreversable action which removes all wallet data from your browser, make sure to backup your data first. WE RETAIN NO BACKUPS OF YOUR WALLET DATA.
`,
- callback: () => {
+ callback: async () => {
localStorage.clear()
sessionStorage.clear()
// @ts-ignore
diff --git a/src/rigs/confirm-action.js b/src/rigs/confirm-action.js
index 1e43ca1..4d220a1 100644
--- a/src/rigs/confirm-action.js
+++ b/src/rigs/confirm-action.js
@@ -3,6 +3,10 @@ import {
formDataEntries,
} from '../helpers/utils.js'
+import {
+ DIALOG_STATUS,
+} from '../helpers/constants.js'
+
export let confirmActionRig = (async function (globals) {
'use strict';
@@ -26,6 +30,7 @@ export let confirmActionRig = (async function (globals) {
actionType: 'warn',
actionClasses: {
info: 'bg-info dark bg-info-hover',
+ infoo: 'outline brd-info info dark light-hover bg-info-hover',
warn: 'outline brd-warn warn dark-hover bg-warn-hover',
dang: 'outline brd-dang dang light-hover bg-dang-hover',
},
@@ -79,16 +84,7 @@ export let confirmActionRig = (async function (globals) {
`,
alert: state => html``,
- // alert: state => html`
- //
- //
- // This is an irreversable action, make sure to backup first.
- //
- //
- // `,
- content: state => html`
- ${state.header(state)}
-
+ fields: state => html`
Are you sure you want to ${state.action} ${
@@ -96,6 +92,11 @@ export let confirmActionRig = (async function (globals) {
}?
+ `,
+ content: state => html`
+ ${state.header(state)}
+
+ ${state.fields(state)}
${state.footer(state)}
`,
@@ -108,8 +109,17 @@ export let confirmActionRig = (async function (globals) {
if (fde?.intent === 'act') {
// state.elements.dialog.returnValue = String(fde.intent)
- state.callback?.(state, fde)
- confirmAction.close(fde.intent)
+ let res = await state.callback?.(state, fde)
+
+ if (
+ res.state.status === DIALOG_STATUS.SUCCESS ||
+ res.state.status === DIALOG_STATUS.ERROR
+ ) {
+ // state.elements.dialog?.querySelector('progress')?.remove()
+ state.elements.progress?.remove?.()
+
+ confirmAction.close(fde.intent)
+ }
}
},
},
diff --git a/src/rigs/crowdnode-tx.js b/src/rigs/crowdnode-tx.js
new file mode 100644
index 0000000..66b86c4
--- /dev/null
+++ b/src/rigs/crowdnode-tx.js
@@ -0,0 +1,135 @@
+import { lit as html } from '../helpers/lit.js'
+import {
+ formDataEntries,
+} from '../helpers/utils.js'
+
+import {
+ DIALOG_STATUS,
+} from '../helpers/constants.js'
+
+import { DialogContructor } from '../components/modal.js'
+
+export const crowdnodeTransactionRig = (() => {
+ 'use strict';
+
+ // let {
+ // mainApp, setupDialog,
+ // } = globals
+
+ let dialogConfig = {
+ state: {
+ name: 'CrowdNode Deposit / Withdraw',
+ actionTxt: 'Do It!',
+ actionAlt: 'Yeah, really do this!',
+ cancelTxt: 'Cancel',
+ cancelAlt: `Cancel`,
+ closeTxt: html` `,
+ closeAlt: `Cancel & Close`,
+ action: '',
+ target: '',
+ targetFallback: 'this wallet',
+ actionType: 'warn',
+ actionClasses: {
+ info: 'bg-info dark bg-info-hover',
+ infoo: 'outline brd-info info dark light-hover bg-info-hover',
+ warn: 'outline brd-warn warn dark-hover bg-warn-hover',
+ dang: 'outline brd-dang dang light-hover bg-dang-hover',
+ },
+ showCancelBtn: true,
+ showActBtn: true,
+ },
+ markup: {},
+ events: {},
+ // appElement: mainApp,
+ appElement: document.body,
+ }
+
+ let crowdnodeTransaction = new DialogContructor(dialogConfig)
+
+ console.log('Modal.js Dialog', crowdnodeTransaction)
+
+ dialogConfig.events.submit = async function (event) {
+ event.preventDefault()
+ event.stopPropagation()
+
+ let fde = formDataEntries(event)
+
+ if (fde?.intent === 'act') {
+ // state.elements.dialog.returnValue = String(fde.intent)
+ let res = await this.state.value.callback?.(this.state.value, fde)
+
+ if (
+ res.state.value.status === DIALOG_STATUS.SUCCESS ||
+ res.state.value.status === DIALOG_STATUS.ERROR
+ ) {
+ // this.elements.dialog?.querySelector('progress')?.remove()
+ this.elements.progress?.remove?.()
+
+ this.elements.dialog?.close(fde.intent)
+ }
+ }
+ }
+
+ dialogConfig.markup.alert = html``
+ dialogConfig.markup.submitIcon = ``
+ // dialogConfig.markup.submitIcon = html`
+ //
+ //
+ //
+ // `
+ // dialogConfig.markup.cancelBtn = html`
+ //
+ // ${crowdnodeTransaction.state.value.cancelTxt}
+ //
+ // `
+ // dialogConfig.markup.actionBtn = html`
+ //
+ // ${crowdnodeTransaction.markup.submitIcon}
+ // ${crowdnodeTransaction.state.value.actionTxt}
+ //
+ // `
+ // dialogConfig.markup.footer = html`
+ //
+ // `
+ // dialogConfig.markup.fields = html`
+ //
+ //
+ // Are you sure you want to ${crowdnodeTransaction.state.value.action} ${
+ // crowdnodeTransaction.state.value.target || crowdnodeTransaction.state.value.targetFallback
+ // }?
+ //
+ //
+ // `
+ // dialogConfig.markup.content = () => html`
+ // ${crowdnodeTransaction.markup.header}
+
+ // ${crowdnodeTransaction.markup.fields}
+
+ // ${crowdnodeTransaction.markup.footer}
+ // `
+
+ crowdnodeTransaction.updateConfig(dialogConfig)
+
+ return crowdnodeTransaction
+})();
+
+export default crowdnodeTransactionRig
\ No newline at end of file
diff --git a/src/rigs/send-or-request.js b/src/rigs/send-or-request.js
index a2d94ac..ac290f2 100644
--- a/src/rigs/send-or-request.js
+++ b/src/rigs/send-or-request.js
@@ -38,6 +38,7 @@ export let sendOrReceiveRig = (async function (globals) {
closeTxt: html` `,
closeAlt: `Close`,
action: 'send',
+ hideAddressee: false,
submitIcon: state => {
const icon = {
send: html`
@@ -180,26 +181,56 @@ export let sendOrReceiveRig = (async function (globals) {
`
},
+ cashSend: state => html`
+
+
+ Use CashSend
+
+
+
+
+ `,
+ addressee: state => {
+ if (state.hideAddressee) {
+ return html`
+
+ `
+ }
+
+ return html`
+
+
+
+ ${state.qrScanBtn(state)}
+
+ `
+ },
content: state => html`
${state.header(state)}
-
-
-
- ${state.qrScanBtn(state)}
-
+ ${state.addressee(state)}
@@ -228,18 +259,7 @@ export let sendOrReceiveRig = (async function (globals) {
${state.fundAmountBtns(state)}
-
-
- Use CashSend
-
-
-
-
+ ${state.cashSend(state)}
@@ -444,6 +464,10 @@ export let sendOrReceiveRig = (async function (globals) {
inWallet = Object.values(contact?.incoming)?.[0]
}
+ console.log('send or request', {
+ to, contact, outWallet, inWallet
+ })
+
if (!inWallet) {
// state.wallet.addressIndex = (
// state.wallet?.addressIndex ?? -1
@@ -518,7 +542,7 @@ export let sendOrReceiveRig = (async function (globals) {
}
let leftoverBalance = walletFunds.balance - amount
- let fullTransfer = leftoverBalance <= 0.0010_0200
+ let fullTransfer = leftoverBalance > 0 && leftoverBalance <= 0.0010_0200
// let fullTransfer = leftoverBalance <= 0.0001_0200
if (
@@ -542,6 +566,7 @@ export let sendOrReceiveRig = (async function (globals) {
state.wallet.accountIndex,
state.wallet.addressIndex,
)
+
let amountNeeded = fixedDash(roundUsing(Math.floor, Math.abs(
walletFunds.balance - Number(fde.amount)
)))
diff --git a/src/rigs/show-error.js b/src/rigs/show-error.js
index 0e590d5..b59d84f 100644
--- a/src/rigs/show-error.js
+++ b/src/rigs/show-error.js
@@ -60,7 +60,7 @@ export async function showErrorDialog(options) {
content: state => html`
${state.header(state)}
-
+
diff --git a/src/secp.js b/src/secp.js
new file mode 100644
index 0000000..f49b0e8
--- /dev/null
+++ b/src/secp.js
@@ -0,0 +1,11 @@
+import '../node_modules/@dashincubator/secp256k1/secp256k1.js';
+
+// @ts-ignore
+const secp = window?.nobleSecp256k1 || globalThis?.nobleSecp256k1 || window?.Secp256k1 || globalThis?.Secp256k1
+
+// @ts-ignore
+window.Secp256k1 = secp
+
+export const Secp256k1 = secp
+
+export default secp
diff --git a/src/styles/components.css b/src/styles/components.css
index 43c7933..6751960 100644
--- a/src/styles/components.css
+++ b/src/styles/components.css
@@ -116,6 +116,9 @@
display: flex;
}
+.integration-sect {
+ padding: 0 1rem;
+}
.integration-sect > section > header {
flex-direction: column;
align-items: start;
@@ -140,6 +143,34 @@
text-decoration: none;
}
+.card {
+ border-radius: 1rem;
+ overflow: auto;
+ flex: 1 1 auto;
+ max-width: 49%;
+ overflow: hidden;
+}
+.card header,
+.card footer {
+ padding: 1rem 0;
+}
+
+.card header a,
+.card header a:active,
+.card header a:focus,
+.card header a:hover {
+ color: var(--fc);
+ text-decoration: none;
+}
+.card section {
+ padding: .25rem 0;
+}
+.card fieldset {
+ min-width: auto;
+}
+.card footer button {
+}
+
@@ -150,6 +181,21 @@
.cols > section {
padding: 0;
}
+
+ .card {
+ max-width: 32.5%;
+ padding: 0 1rem;
+ }
+ .card header,
+ .card footer {
+ padding: 1rem 0;
+ }
+ .card section {
+ padding: .25rem 0;
+ }
+ .integration-sect {
+ padding: 0;
+ }
}
@media (min-width: 980px) {
.cols {
diff --git a/src/styles/dialog.css b/src/styles/dialog.css
index 75c3b1b..25ecf42 100644
--- a/src/styles/dialog.css
+++ b/src/styles/dialog.css
@@ -197,7 +197,7 @@ dialog > form > fieldset input + p {
font-weight: 400;
margin: .5rem 0;
}
-dialog > form > fieldset p {
+dialog > form fieldset p {
display: flex;
padding: 0;
margin: .8rem;
@@ -217,7 +217,7 @@ dialog > form > fieldset div + p {
margin: 0 0 0 1rem;
text-align: left;
}
-dialog > form > fieldset p > span {
+dialog > form fieldset p > span {
padding: .25rem;
border: 1px solid var(--dark-500);
}
diff --git a/src/styles/form.css b/src/styles/form.css
index c1fc1b1..d1a4aca 100644
--- a/src/styles/form.css
+++ b/src/styles/form.css
@@ -494,7 +494,7 @@ label {
}
label > input[type=checkbox],
label + input[type=checkbox] {
- width: 2rem;
+ width: 1.25rem;
}
div.switch {
@@ -739,6 +739,25 @@ form[name="network"] {
cursor: default;
}
+main form header {
+ margin: 0 auto;
+ min-height: auto;
+ /* width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ flex-direction: column-reverse; */
+}
+
+.card footer {
+ gap: .25rem;
+}
+
+.card footer button {
+ padding: 0.63rem .25rem;
+ flex: 1 1 50%;
+}
+
@media (min-width: 650px) {
main form {
@@ -776,4 +795,8 @@ form[name="network"] {
form > article > figure figcaption + div.big {
font-size: 3.75rem;
} */
+
+ .card footer button {
+ padding: 0.63rem 1rem;
+ }
}
\ No newline at end of file
diff --git a/src/styles/motion.css b/src/styles/motion.css
index 26aa428..85cff62 100644
--- a/src/styles/motion.css
+++ b/src/styles/motion.css
@@ -1,16 +1,16 @@
@-webkit-keyframes await-progress {
- 0% {
- background-position: -322px;
+ 0% {
+ background-position: -150%;
}
100% {
- background-position: 322px;
+ background-position: 200%;
}
}
@keyframes await-progress {
- 0% {
- background-position: -322px;
+ 0% {
+ background-position: -150%;
}
100% {
- background-position: 322px;
+ background-position: 200%;
}
}
diff --git a/src/styles/progress.css b/src/styles/progress.css
index 1ad2c4f..6d30564 100644
--- a/src/styles/progress.css
+++ b/src/styles/progress.css
@@ -1,19 +1,3 @@
-progress:indeterminate {
- background: linear-gradient(
- 90deg,
- #0000 0%,
- #0000 50%,
- var(--info) 100%
- );
-}
-progress.recording:indeterminate {
- background: linear-gradient(
- 90deg,
- var(--livea) 0%,
- var(--live) 50%,
- var(--livea) 100%
- );
-}
progress.pending,
progress.pending[role] {
position: absolute;
@@ -26,14 +10,15 @@ progress.pending[role] {
padding: 0;
border: none;
background-color: transparent;
- background-size: auto;
+ /* background-size: auto; */
+ background-size: 50% 100%;
background-repeat: no-repeat;
background-position: 0 0;
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
border: 0 solid transparent;
- visibility: hidden;
+ /* visibility: hidden; */
}
progress.recording,
progress.recording[role] {
@@ -52,11 +37,3 @@ progress.pending:indeterminate {
-webkit-animation: await-progress 2.5s ease-in-out infinite;
animation: await-progress 2.5s ease-in-out infinite;
}
-
-
-/* form[name=toggle_relay]:has(input[type=checkbox]:checked) {
- border-bottom: .25rem solid var(--dang);
-} */
-form[name=toggle_relay]:has(input[type=checkbox]:checked) progress {
- visibility: visible;
-}
diff --git a/src/styles/theme.css b/src/styles/theme.css
index c8e5830..55d1c2e 100644
--- a/src/styles/theme.css
+++ b/src/styles/theme.css
@@ -19,6 +19,10 @@
--light-500: #004470;
--light-600: #003e66;
+ --card-100: hsl(200deg 80% 60% / 15%);
+ --card-100: #00447066;
+
+
--grayscale-gray-400: #9DA6A6;
--c: var(--dark-900);
@@ -140,11 +144,11 @@ a:hover {
}
svg {
- fill: currentColor;
vertical-align: bottom;
}
-svg path {
+svg g:not(.lock),
+svg path:not(.lock) {
fill: currentColor;
}
@@ -316,6 +320,11 @@ th {
border-radius: 6.25rem;
}
+.card {
+ background-color: var(--card-100);
+ /* background-color: var(--dark-600); */
+}
+
.cols > section > div {
background-color: var(--nav-bg);
}
From 5906372a7994cad32c530aa3fb58c6bdbe5dac79 Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Fri, 20 Sep 2024 04:41:36 -0600
Subject: [PATCH 03/12] refactor: :recycle: add CrowdNode lib to imports &
cleanup
---
src/helpers/constants.js | 46 ++++++++++++++++++++++-
src/imports.js | 17 +++++++--
src/index.html | 1 +
src/rigs/crowdnode-tx.js | 80 ++++++++--------------------------------
src/styles/dialog.css | 3 ++
5 files changed, 77 insertions(+), 70 deletions(-)
diff --git a/src/helpers/constants.js b/src/helpers/constants.js
index e85f271..d7a8d1f 100644
--- a/src/helpers/constants.js
+++ b/src/helpers/constants.js
@@ -153,4 +153,48 @@ export const DIALOG_STATUS = {
LOADING,
SUCCESS,
ERROR
-}
\ No newline at end of file
+}
+
+export const CROWDNODE = {
+ offset: 20000,
+ duffs: 100000000,
+ satoshis: 100000000,
+ depositMinimum: 100000,
+ stakeMinimum: 50000000,
+
+ /**
+ * @type {Record}
+ */
+ requests: {
+ acceptTerms: 65536,
+ offset: 20000,
+ signupForApi: 131072,
+ toggleInstantPayout: 4096,
+ withdrawMin: 1,
+ withdrawMax: 1000,
+ },
+
+ /**
+ * @type {Record}
+ */
+ messages: {
+ PleaseAcceptTerms: 2,
+ WelcomeToCrowdNodeBlockChainAPI: 4,
+ DepositReceived: 8,
+ WithdrawalQueued: 16,
+ WithdrawalFailed: 32,
+ AutoWithdrawalEnabled: 64,
+ AutoWithdrawalDisabled: 128,
+ },
+
+ /**
+ * @type {Record}
+ */
+ responses: {},
+}
+
+CROWDNODE.responses = Object.fromEntries(
+ Object.entries(CROWDNODE.messages).map(
+ ([k,v]) => [v,k]
+ )
+)
diff --git a/src/imports.js b/src/imports.js
index 81fb104..985bf1c 100644
--- a/src/imports.js
+++ b/src/imports.js
@@ -25,6 +25,9 @@ import '../node_modules/@dashincubator/ripemd160/ripemd160.js';
import '../node_modules/crypticstorage/cryptic.js';
import '../node_modules/dashwallet/dashwallet.js';
import '../node_modules/localforage/dist/localforage.js';
+import '../node_modules/crowdnode/dashcore-lit.js';
+import '../node_modules/crowdnode/dashapi.js';
+import '../node_modules/crowdnode/crowdnode.js';
import * as DashTxTypes from '../node_modules/dashtx/dashtx.js';
import * as DashKeysTypes from '../node_modules/dashkeys/dashkeys.js';
@@ -38,6 +41,9 @@ import * as Secp256k1Types from '../node_modules/@dashincubator/secp256k1/secp25
import * as CrypticTypes from '../node_modules/crypticstorage/cryptic.js';
import * as CrypticStorageTypes from '../node_modules/crypticstorage/storage.js';
import * as DashWalletTypes from '../node_modules/dashwallet/dashwallet.js';
+import * as DashCoreTypes from '../node_modules/crowdnode/dashcore-lit.js';
+import * as DashApiTypes from '../node_modules/crowdnode/dashapi.js';
+import * as CrowdNodeTypes from '../node_modules/crowdnode/crowdnode.js';
// import * as LocalForageTypes from '../node_modules/localforage/dist/localforage.js';
/** @type {DashTxTypes} */
@@ -69,11 +75,17 @@ export let CrypticStorage =
window?.CrypticStorage || globalThis?.CrypticStorage;
/** @type {DashWalletTypes} */
export let DashWallet = window?.Wallet || globalThis?.Wallet;
+/** @type {CrowdNodeTypes} */
+export let CrowdNode = window?.CrowdNode || globalThis?.CrowdNode
export let localforage =
window?.localforage || globalThis?.localforage;
export default {
+ Base58Check,
+ CrowdNode,
+ Cryptic,
+ CrypticStorage,
DashWallet,
DashTx,
DashKeys,
@@ -81,10 +93,7 @@ export default {
DashPhrase,
DashSight,
DashSocket,
- Base58Check,
+ localforage,
RIPEMD160,
Secp256k1,
- Cryptic,
- CrypticStorage,
- localforage,
};
diff --git a/src/index.html b/src/index.html
index 9722a8f..71a1ac2 100644
--- a/src/index.html
+++ b/src/index.html
@@ -47,6 +47,7 @@
}
}
+
diff --git a/src/rigs/crowdnode-tx.js b/src/rigs/crowdnode-tx.js
index 66b86c4..6f29677 100644
--- a/src/rigs/crowdnode-tx.js
+++ b/src/rigs/crowdnode-tx.js
@@ -12,10 +12,6 @@ import { DialogContructor } from '../components/modal.js'
export const crowdnodeTransactionRig = (() => {
'use strict';
- // let {
- // mainApp, setupDialog,
- // } = globals
-
let dialogConfig = {
state: {
name: 'CrowdNode Deposit / Withdraw',
@@ -40,13 +36,12 @@ export const crowdnodeTransactionRig = (() => {
},
markup: {},
events: {},
- // appElement: mainApp,
appElement: document.body,
}
let crowdnodeTransaction = new DialogContructor(dialogConfig)
- console.log('Modal.js Dialog', crowdnodeTransaction)
+ // console.log('Modal.js Dialog', crowdnodeTransaction)
dialogConfig.events.submit = async function (event) {
event.preventDefault()
@@ -55,77 +50,32 @@ export const crowdnodeTransactionRig = (() => {
let fde = formDataEntries(event)
if (fde?.intent === 'act') {
- // state.elements.dialog.returnValue = String(fde.intent)
- let res = await this.state.value.callback?.(this.state.value, fde)
+ let res = await crowdnodeTransaction.state.value.callback?.(
+ crowdnodeTransaction.state,
+ fde,
+ )
+
+ // console.log('crowdnodeTransaction submit res', res)
if (
res.state.value.status === DIALOG_STATUS.SUCCESS ||
res.state.value.status === DIALOG_STATUS.ERROR
) {
- // this.elements.dialog?.querySelector('progress')?.remove()
- this.elements.progress?.remove?.()
+ crowdnodeTransaction.elements.progress?.remove?.()
- this.elements.dialog?.close(fde.intent)
+ crowdnodeTransaction.elements.dialog.returnValue = String(fde.intent)
+ crowdnodeTransaction.elements.dialog?.close(String(fde.intent))
}
+ } else {
+ crowdnodeTransaction.elements.progress?.remove?.()
+
+ crowdnodeTransaction.elements.dialog.returnValue = 'cancel'
+ crowdnodeTransaction.elements.dialog?.close('cancel')
}
}
dialogConfig.markup.alert = html``
dialogConfig.markup.submitIcon = ``
- // dialogConfig.markup.submitIcon = html`
- //
- //
- //
- // `
- // dialogConfig.markup.cancelBtn = html`
- //
- // ${crowdnodeTransaction.state.value.cancelTxt}
- //
- // `
- // dialogConfig.markup.actionBtn = html`
- //
- // ${crowdnodeTransaction.markup.submitIcon}
- // ${crowdnodeTransaction.state.value.actionTxt}
- //
- // `
- // dialogConfig.markup.footer = html`
- //
- // `
- // dialogConfig.markup.fields = html`
- //
- //
- // Are you sure you want to ${crowdnodeTransaction.state.value.action} ${
- // crowdnodeTransaction.state.value.target || crowdnodeTransaction.state.value.targetFallback
- // }?
- //
- //
- // `
- // dialogConfig.markup.content = () => html`
- // ${crowdnodeTransaction.markup.header}
-
- // ${crowdnodeTransaction.markup.fields}
-
- // ${crowdnodeTransaction.markup.footer}
- // `
crowdnodeTransaction.updateConfig(dialogConfig)
diff --git a/src/styles/dialog.css b/src/styles/dialog.css
index 25ecf42..5be19e4 100644
--- a/src/styles/dialog.css
+++ b/src/styles/dialog.css
@@ -181,6 +181,9 @@ dialog > form > fieldset div:has(input + div) {
border-radius: 6.25rem;
border: 1px solid var(--dark-600);
}
+dialog > form > fieldset input[type="range"] {
+ padding: 0;
+}
dialog > form > fieldset input + p,
dialog > form > fieldset label {
text-align: left;
From d63ca49ba3ace26ad02f8e65ad1ff20079c8ea49 Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Fri, 20 Sep 2024 04:42:33 -0600
Subject: [PATCH 04/12] refactor: :fire: cleanup modal.js
---
src/components/modal.js | 174 ++++------------------------------------
1 file changed, 16 insertions(+), 158 deletions(-)
diff --git a/src/components/modal.js b/src/components/modal.js
index 781e7a5..561e1f7 100644
--- a/src/components/modal.js
+++ b/src/components/modal.js
@@ -143,41 +143,11 @@ export const DialogContructor = (() => {
this.events = {
input: event => {
- // let {
- // // @ts-ignore
- // name: fieldName, form,
- // } = event?.target
-
- // console.log('handle input', {
- // fieldName,
- // form,
- // })
-
- if (
- event?.target?.validity?.patternMismatch &&
- event?.target?.type !== 'checkbox'
- ) {
- event.preventDefault()
- let label = event.target?.previousElementSibling?.textContent?.trim()
- if (label) {
- event.target.setCustomValidity(`Invalid ${label}`)
- }
- } else {
- event.target.setCustomValidity('')
- }
- event.target.reportValidity()
},
change: event => {
- // let {
- // // @ts-ignore
- // name: fieldName, form,
- // } = event?.target
-
- // console.log('handle change', {
- // fieldName,
- // form,
- // })
-
+ },
+ blur: event => {
+ // event.preventDefault()
if (
event?.target?.validity?.patternMismatch &&
event?.target?.type !== 'checkbox'
@@ -192,26 +162,11 @@ export const DialogContructor = (() => {
}
event.target.reportValidity()
},
- blur: event => {
- // event.preventDefault()
- // console.log(
- // 'handle blur',
- // event,
- // )
- },
focusout: event => {
// event.preventDefault()
- // console.log(
- // 'handle focus out',
- // event,
- // )
},
focusin: event => {
// event.preventDefault()
- // console.log(
- // 'handle focus in',
- // event,
- // )
},
drop: event => {
event.preventDefault()
@@ -228,19 +183,10 @@ export const DialogContructor = (() => {
render: (
state,
) => {
- // console.log(
- // 'handle dialog render',
- // state,
- // )
},
show: (
state,
) => {
- // console.log(
- // 'handle dialog show',
- // state,
- // )
-
// focus first input
this.elements.form.querySelector(
'input'
@@ -253,12 +199,6 @@ export const DialogContructor = (() => {
event.preventDefault()
removeAllListeners.bind(this)
- // console.log(
- // 'handle dialog close',
- // event,
- // event.target === this.elements.dialog,
- // this.elements.dialog.returnValue
- // )
this.state.value.status = DIALOG_STATUS.NOT_LOADING
this.elements.dialog?.querySelector('progress')?.remove()
@@ -267,21 +207,10 @@ export const DialogContructor = (() => {
} else {
resolve('cancel')
}
- // console.log(
- // 'DIALOG handleClose',
- // modal.rendered[this.slugs.dialog],
- // )
setTimeout(t => {
- // modal.rendered[this.slugs.dialog] = null
this.state.value.rendered = null
event?.target?.remove()
- // console.log(
- // 'DIALOG handleClose setTimeout',
- // this.state.value.delay,
- // // modal.rendered[this.slugs.dialog],
- // modal.rendered,
- // )
}, this.state.value.delay)
},
submit: event => {
@@ -291,11 +220,6 @@ export const DialogContructor = (() => {
this.elements.dialog.returnValue = String(fde.intent)
- // console.log(
- // 'handleSubmit',
- // [event],
- // )
-
this.elements.dialog.close(String(fde.intent))
},
reset: event => {
@@ -304,19 +228,10 @@ export const DialogContructor = (() => {
'close',
this.events.reset
)
- // console.log(
- // 'handleReset',
- // [event.target],
- // )
this.elements.dialog.close('cancel')
},
click: event => {
if (event.target === this.elements.dialog) {
- // console.log(
- // 'handle dialog backdrop click',
- // event,
- // event.target === this.elements.dialog
- // )
this.elements.dialog.close('cancel')
}
},
@@ -330,7 +245,6 @@ export const DialogContructor = (() => {
this.elements.form = formElement
this.elements.progress = progressElement
-
this.element = this.elements.dialog
progressElement.classList.add('pending')
@@ -344,7 +258,6 @@ export const DialogContructor = (() => {
formElement.name = `${this.slugs.form}`
formElement.method = 'dialog'
- // formElement.innerHTML = this.markup.content
formElement.innerHTML = this.markup.content()
dialogElement.insertAdjacentElement(
@@ -360,16 +273,12 @@ export const DialogContructor = (() => {
removeAllListeners.call(this)
addListeners.call(this, resolve, reject)
console.log('modal.js dialog show', this.elements.dialog)
- // if (
- // !this.state.value.rendered &&
- // !el.contains(this.elements.dialog)
- // ) {
- this.render({
- el,
- // cfg: config,
- position: 'afterend'
- })
- // }
+
+ this.render({
+ el,
+ position: 'afterend'
+ })
+
this.elements.dialog.show()
this.events.show?.(this)
callback?.()
@@ -383,16 +292,13 @@ export const DialogContructor = (() => {
removeAllListeners.call(this)
addListeners.call(this, resolve, reject)
console.log('modal.js dialog showModal', this, this.elements.dialog)
- // if (
- // !this.state.value.rendered &&
- // !el.contains(this.elements.dialog)
- // ) {
- this.render({
- el,
- // cfg: config,
- position: 'afterend'
- })
- // }
+
+ this.render({
+ el,
+ // cfg: config,
+ position: 'afterend'
+ })
+
this.elements.dialog.showModal()
this.events.show?.(this)
callback?.()
@@ -412,12 +318,6 @@ export const DialogContructor = (() => {
console.log('Dialog updateConfig TOP', config)
for (let param in config) {
- // if (param === 'markup') {
- // this[param].value = {
- // ...this[param].value,
- // ...(config[param] || {}),
- // }
- // } else {
if ('value' in this[param]) {
this[param].value = {
...this[param].value,
@@ -429,7 +329,6 @@ export const DialogContructor = (() => {
...(config[param] || {}),
}
}
- // }
}
console.log('Dialog updateConfig BOT', this)
@@ -446,11 +345,6 @@ export const DialogContructor = (() => {
}) => {
console.log('dialog render', this, dl)
- // this.elements.form?.removeEventListener?.(
- // 'submit',
- // this.events.submit,
- // )
-
if (el !== this.appElement) {
this.appElement = el
}
@@ -461,14 +355,8 @@ export const DialogContructor = (() => {
this.elements.dialog.id = this.slugs.dialog
this.elements.form.name = this.slugs.form
- // this.elements.form.innerHTML = this.markup.content
this.elements.form.innerHTML = this.markup.content()
- // this.elements.form.addEventListener(
- // 'submit',
- // this.events.submit,
- // )
-
console.log('DIALOG RENDER STATE', this.state.value, cfg)
console.log('DIALOG RENDER', position, this.slugs.dialog)
@@ -480,18 +368,12 @@ export const DialogContructor = (() => {
'beforebegin',
this.elements.progress,
)
-
- // document.body.insertAdjacentHTML(
- // 'afterbegin',
- // ` `,
- // )
}
if (
this.state.value.status === DIALOG_STATUS.SUCCESS ||
this.state.value.status === DIALOG_STATUS.ERROR
) {
- // document.getElementById('pageLoader')?.remove()
this.elements.dialog.querySelector('progress')?.remove()
}
@@ -507,37 +389,13 @@ export const DialogContructor = (() => {
)
}
- // console.log('DIALOG RENDER', state, position, state.slugs.dialog, modal.rendered)
-
this.events.render(this.state)
return this
}
-
- // const updateSelf = (cfg, methods = []) => {
- // for (let mthd of methods) {
- // this[mthd] = {
- // ...this[mthd],
- // ...(cfg[mthd] || {}),
- // }
- // }
- // }
- // updateSelf(cfg, [
- // 'state', 'slugs', 'events', 'elements', 'templates'
- // ])
-
- // state.render = render
}
return dl
})();
-// export function Modal(config) {
-// let dialog = new DialogContructor(config)
-
-// console.log('Modal.js Dialog', dialog)
-
-// return dialog
-// }
-
export default DialogContructor
From 4e1dbd8ec8d44f0ae90d99ce01e3fb13c0b0072a Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Fri, 20 Sep 2024 04:43:45 -0600
Subject: [PATCH 05/12] refactor: :recycle: cleanup utils.js & remove unused
path-to-regexp.js
---
src/helpers/utils.js | 44 ++--
src/libs/path-to-regexp.js | 490 -------------------------------------
2 files changed, 19 insertions(+), 515 deletions(-)
delete mode 100644 src/libs/path-to-regexp.js
diff --git a/src/helpers/utils.js b/src/helpers/utils.js
index f613de1..2730418 100644
--- a/src/helpers/utils.js
+++ b/src/helpers/utils.js
@@ -490,15 +490,7 @@ export function createSignal(initialValue) {
return {
get value() {
- if (
- currentSignal //&&
- // currentSignal !== globalDerivedValue
- ) {
- console.log(
- 'currentSignal === derived',
- {currentSignal, derived, globalDerivedValue},
- currentSignal === globalDerivedValue,
- )
+ if (currentSignal) {
on(currentSignal)
}
return _value;
@@ -712,22 +704,24 @@ export function DashURLSearchParams(params) {
let searchParams
let qry = {}
- Object.defineProperty(this, "entries", {
- enumerable: false,
- configurable: false,
- writable: false,
- value: () => Object.entries(qry),
- });
- Object.defineProperty(this, "toString", {
- enumerable: false,
- configurable: false,
- writable: false,
- value: () => this.entries().map(p => p.join('=')).join('&'),
- });
- Object.defineProperty(this, "size", {
- get() { return this.entries().length },
- enumerable: false,
- configurable: false,
+ Object.defineProperties(this, {
+ entries: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: () => Object.entries(qry),
+ },
+ toString: {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: () => this.entries().map(p => p.join('=')).join('&'),
+ },
+ size: {
+ enumerable: false,
+ configurable: false,
+ get() { return this.entries().length },
+ },
});
if (typeof params === 'string' && params !== '') {
diff --git a/src/libs/path-to-regexp.js b/src/libs/path-to-regexp.js
deleted file mode 100644
index 6394b64..0000000
--- a/src/libs/path-to-regexp.js
+++ /dev/null
@@ -1,490 +0,0 @@
-// @ts-nocheck
-
-/**
- * https://unpkg.com/path-to-regexp@6.2.1/dist/index.js
- * https://github.com/pillarjs/path-to-regexp
- * https://github.com/expressjs/express/blob/master/lib/router/layer.js
- */
-
-/**
- * Tokenize input string.
- */
-function lexer(str) {
- var tokens = [];
- var i = 0;
- while (i < str.length) {
- var char = str[i];
- if (char === '*' || char === '+' || char === '?') {
- tokens.push({ type: 'MODIFIER', index: i, value: str[i++] });
- continue;
- }
- if (char === '\\') {
- tokens.push({ type: 'ESCAPED_CHAR', index: i++, value: str[i++] });
- continue;
- }
- if (char === '{') {
- tokens.push({ type: 'OPEN', index: i, value: str[i++] });
- continue;
- }
- if (char === '}') {
- tokens.push({ type: 'CLOSE', index: i, value: str[i++] });
- continue;
- }
- if (char === ':') {
- var name = '';
- var j = i + 1;
- while (j < str.length) {
- var code = str.charCodeAt(j);
- if (
- // `0-9`
- (code >= 48 && code <= 57) ||
- // `A-Z`
- (code >= 65 && code <= 90) ||
- // `a-z`
- (code >= 97 && code <= 122) ||
- // `_`
- code === 95
- ) {
- name += str[j++];
- continue;
- }
- break;
- }
- if (!name) throw new TypeError('Missing parameter name at '.concat(i));
- tokens.push({ type: 'NAME', index: i, value: name });
- i = j;
- continue;
- }
- if (char === '(') {
- var count = 1;
- var pattern = '';
- var j = i + 1;
- if (str[j] === '?') {
- throw new TypeError('Pattern cannot start with "?" at '.concat(j));
- }
- while (j < str.length) {
- if (str[j] === '\\') {
- pattern += str[j++] + str[j++];
- continue;
- }
- if (str[j] === ')') {
- count--;
- if (count === 0) {
- j++;
- break;
- }
- } else if (str[j] === '(') {
- count++;
- if (str[j + 1] !== '?') {
- throw new TypeError(
- 'Capturing groups are not allowed at '.concat(j),
- );
- }
- }
- pattern += str[j++];
- }
- if (count) throw new TypeError('Unbalanced pattern at '.concat(i));
- if (!pattern) throw new TypeError('Missing pattern at '.concat(i));
- tokens.push({ type: 'PATTERN', index: i, value: pattern });
- i = j;
- continue;
- }
- tokens.push({ type: 'CHAR', index: i, value: str[i++] });
- }
- tokens.push({ type: 'END', index: i, value: '' });
- return tokens;
-}
-
-/**
- * Parse a string for the raw tokens.
- */
-export function parse(str, options) {
- if (options === void 0) {
- options = {};
- }
- var tokens = lexer(str);
- var _a = options.prefixes,
- prefixes = _a === void 0 ? './' : _a;
- var defaultPattern = '[^'.concat(
- escapeString(options.delimiter || '/#?'),
- ']+?',
- );
- var result = [];
- var key = 0;
- var i = 0;
- var path = '';
- var tryConsume = function (type) {
- if (i < tokens.length && tokens[i].type === type) return tokens[i++].value;
- };
- var mustConsume = function (type) {
- var value = tryConsume(type);
- if (value !== undefined) return value;
- var _a = tokens[i],
- nextType = _a.type,
- index = _a.index;
- throw new TypeError(
- 'Unexpected '
- .concat(nextType, ' at ')
- .concat(index, ', expected ')
- .concat(type),
- );
- };
- var consumeText = function () {
- var result = '';
- var value;
- while ((value = tryConsume('CHAR') || tryConsume('ESCAPED_CHAR'))) {
- result += value;
- }
- return result;
- };
- while (i < tokens.length) {
- var char = tryConsume('CHAR');
- var name = tryConsume('NAME');
- var pattern = tryConsume('PATTERN');
- if (name || pattern) {
- var prefix = char || '';
- if (prefixes.indexOf(prefix) === -1) {
- path += prefix;
- prefix = '';
- }
- if (path) {
- result.push(path);
- path = '';
- }
- result.push({
- name: name || key++,
- prefix: prefix,
- suffix: '',
- pattern: pattern || defaultPattern,
- modifier: tryConsume('MODIFIER') || '',
- });
- continue;
- }
- var value = char || tryConsume('ESCAPED_CHAR');
- if (value) {
- path += value;
- continue;
- }
- if (path) {
- result.push(path);
- path = '';
- }
- var open = tryConsume('OPEN');
- if (open) {
- var prefix = consumeText();
- var name_1 = tryConsume('NAME') || '';
- var pattern_1 = tryConsume('PATTERN') || '';
- var suffix = consumeText();
- mustConsume('CLOSE');
- result.push({
- name: name_1 || (pattern_1 ? key++ : ''),
- pattern: name_1 && !pattern_1 ? defaultPattern : pattern_1,
- prefix: prefix,
- suffix: suffix,
- modifier: tryConsume('MODIFIER') || '',
- });
- continue;
- }
- mustConsume('END');
- }
- return result;
-}
-
-/**
- * Compile a string to a template function for the path.
- */
-export function compile(str, options) {
- return tokensToFunction(parse(str, options), options);
-}
-
-/**
- * Expose a method for transforming tokens into the path function.
- */
-export function tokensToFunction(tokens, options) {
- if (options === void 0) {
- options = {};
- }
- var reFlags = flags(options);
- var _a = options.encode,
- encode =
- _a === void 0
- ? function (x) {
- return x;
- }
- : _a,
- _b = options.validate,
- validate = _b === void 0 ? true : _b;
- // Compile all the tokens into regexps.
- var matches = tokens.map(function (token) {
- if (typeof token === 'object') {
- return new RegExp('^(?:'.concat(token.pattern, ')$'), reFlags);
- }
- });
- return function (data) {
- var path = '';
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (typeof token === 'string') {
- path += token;
- continue;
- }
- var value = data ? data[token.name] : undefined;
- var optional = token.modifier === '?' || token.modifier === '*';
- var repeat = token.modifier === '*' || token.modifier === '+';
- if (Array.isArray(value)) {
- if (!repeat) {
- throw new TypeError(
- 'Expected "'.concat(
- token.name,
- '" to not repeat, but got an array',
- ),
- );
- }
- if (value.length === 0) {
- if (optional) continue;
- throw new TypeError(
- 'Expected "'.concat(token.name, '" to not be empty'),
- );
- }
- for (var j = 0; j < value.length; j++) {
- var segment = encode(value[j], token);
- if (validate && !matches[i].test(segment)) {
- throw new TypeError(
- 'Expected all "'
- .concat(token.name, '" to match "')
- .concat(token.pattern, '", but got "')
- .concat(segment, '"'),
- );
- }
- path += token.prefix + segment + token.suffix;
- }
- continue;
- }
- if (typeof value === 'string' || typeof value === 'number') {
- var segment = encode(String(value), token);
- if (validate && !matches[i].test(segment)) {
- throw new TypeError(
- 'Expected "'
- .concat(token.name, '" to match "')
- .concat(token.pattern, '", but got "')
- .concat(segment, '"'),
- );
- }
- path += token.prefix + segment + token.suffix;
- continue;
- }
- if (optional) continue;
- var typeOfMessage = repeat ? 'an array' : 'a string';
- throw new TypeError(
- 'Expected "'.concat(token.name, '" to be ').concat(typeOfMessage),
- );
- }
- return path;
- };
-}
-
-/**
- * Create path match function from `path-to-regexp` spec.
- */
-export function match(str, options) {
- var keys = [];
- var re = pathToRegexp(str, keys, options);
- return regexpToFunction(re, keys, options);
-}
-
-/**
- * Create a path match function from `path-to-regexp` output.
- */
-export function regexpToFunction(re, keys, options) {
- if (options === void 0) {
- options = {};
- }
- var _a = options.decode,
- decode =
- _a === void 0
- ? function (x) {
- return x;
- }
- : _a;
- return function (pathname) {
- var m = re.exec(pathname);
- if (!m) return false;
- var path = m[0],
- index = m.index;
- var params = Object.create(null);
- var _loop_1 = function (i) {
- if (m[i] === undefined) return 'continue';
- var key = keys[i - 1];
- if (key.modifier === '*' || key.modifier === '+') {
- params[key.name] = m[i]
- .split(key.prefix + key.suffix)
- .map(function (value) {
- return decode(value, key);
- });
- } else {
- params[key.name] = decode(m[i], key);
- }
- };
- for (var i = 1; i < m.length; i++) {
- _loop_1(i);
- }
- return { path: path, index: index, params: params };
- };
-}
-
-/**
- * Escape a regular expression string.
- */
-function escapeString(str) {
- return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1');
-}
-
-/**
- * Get the flags for a regexp from the options.
- */
-function flags(options) {
- return options && options.sensitive ? '' : 'i';
-}
-
-/**
- * Pull out keys from a regexp.
- */
-function regexpToRegexp(path, keys) {
- if (!keys) return path;
- var groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g;
- var index = 0;
- var execResult = groupsRegex.exec(path.source);
- while (execResult) {
- keys.push({
- // Use parenthesized substring match if available, index otherwise
- name: execResult[1] || index++,
- prefix: '',
- suffix: '',
- modifier: '',
- pattern: '',
- });
- execResult = groupsRegex.exec(path.source);
- }
- return path;
-}
-
-/**
- * Transform an array into a regexp.
- */
-function arrayToRegexp(paths, keys, options) {
- var parts = paths.map(function (path) {
- return pathToRegexp(path, keys, options).source;
- });
- return new RegExp('(?:'.concat(parts.join('|'), ')'), flags(options));
-}
-
-/**
- * Create a path regexp from string input.
- */
-function stringToRegexp(path, keys, options) {
- return tokensToRegexp(parse(path, options), keys, options);
-}
-
-/**
- * Expose a function for taking tokens and returning a RegExp.
- */
-export function tokensToRegexp(tokens, keys, options) {
- if (options === void 0) {
- options = {};
- }
- var _a = options.strict,
- strict = _a === void 0 ? false : _a,
- _b = options.start,
- start = _b === void 0 ? true : _b,
- _c = options.end,
- end = _c === void 0 ? true : _c,
- _d = options.encode,
- encode =
- _d === void 0
- ? function (x) {
- return x;
- }
- : _d,
- _e = options.delimiter,
- delimiter = _e === void 0 ? '/#?' : _e,
- _f = options.endsWith,
- endsWith = _f === void 0 ? '' : _f;
- var endsWithRe = '['.concat(escapeString(endsWith), ']|$');
- var delimiterRe = '['.concat(escapeString(delimiter), ']');
- var route = start ? '^' : '';
- // Iterate over the tokens and create our regexp string.
- for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
- var token = tokens_1[_i];
- if (typeof token === 'string') {
- route += escapeString(encode(token));
- } else {
- var prefix = escapeString(encode(token.prefix));
- var suffix = escapeString(encode(token.suffix));
- if (token.pattern) {
- if (keys) keys.push(token);
- if (prefix || suffix) {
- if (token.modifier === '+' || token.modifier === '*') {
- var mod = token.modifier === '*' ? '?' : '';
- route += '(?:'
- .concat(prefix, '((?:')
- .concat(token.pattern, ')(?:')
- .concat(suffix)
- .concat(prefix, '(?:')
- .concat(token.pattern, '))*)')
- .concat(suffix, ')')
- .concat(mod);
- } else {
- route += '(?:'
- .concat(prefix, '(')
- .concat(token.pattern, ')')
- .concat(suffix, ')')
- .concat(token.modifier);
- }
- } else {
- if (token.modifier === '+' || token.modifier === '*') {
- route += '((?:'
- .concat(token.pattern, ')')
- .concat(token.modifier, ')');
- } else {
- route += '('.concat(token.pattern, ')').concat(token.modifier);
- }
- }
- } else {
- route += '(?:'
- .concat(prefix)
- .concat(suffix, ')')
- .concat(token.modifier);
- }
- }
- }
- if (end) {
- if (!strict) route += ''.concat(delimiterRe, '?');
- route += !options.endsWith ? '$' : '(?='.concat(endsWithRe, ')');
- } else {
- var endToken = tokens[tokens.length - 1];
- var isEndDelimited =
- typeof endToken === 'string'
- ? delimiterRe.indexOf(endToken[endToken.length - 1]) > -1
- : endToken === undefined;
- if (!strict) {
- route += '(?:'.concat(delimiterRe, '(?=').concat(endsWithRe, '))?');
- }
- if (!isEndDelimited) {
- route += '(?='.concat(delimiterRe, '|').concat(endsWithRe, ')');
- }
- }
- return new RegExp(route, flags(options));
-}
-
-/**
- * Normalize the given path string, returning a regular expression.
- *
- * An empty array can be passed in for the keys, which will hold the
- * placeholder key descriptions. For example, using `/user/:id`, `keys` will
- * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
- */
-export function pathToRegexp(path, keys, options) {
- if (path instanceof RegExp) return regexpToRegexp(path, keys);
- if (Array.isArray(path)) return arrayToRegexp(path, keys, options);
- return stringToRegexp(path, keys, options);
-}
From 3fad608ec023536d73b68d3a52fc91d062681a1d Mon Sep 17 00:00:00 2001
From: jojobyte <184880+jojobyte@users.noreply.github.com>
Date: Fri, 20 Sep 2024 04:46:50 -0600
Subject: [PATCH 06/12] refactor: :recycle: cleanup & sync CN withdraw dialog
fields
---
src/main.js | 138 +++++++++++++++++++++-------------------------------
1 file changed, 55 insertions(+), 83 deletions(-)
diff --git a/src/main.js b/src/main.js
index f23ab8e..5b3bd81 100644
--- a/src/main.js
+++ b/src/main.js
@@ -139,6 +139,7 @@ let contactsList = await setupContactsList(
}
let contactAccountID = Object.values(contactData.incoming || {})?.[0]?.accountIndex
+
console.log('contact click data', contactData)
let shareAccount = await deriveWalletData(
@@ -812,13 +813,6 @@ async function main() {
})
import('./components/crowdnode-card.js')
.then(async ({ CrowdNodeCard }) => {
- // let crowdnodeTransaction = crowdnodeTransactionRig
- console.log(
- 'crowdnodeTransactionRig',
- crowdnodeTransactionRig,
- crowdnodeTransactionRig.markup.fields,
- )
- // crowdnodeTransactionRig.markup.fields
let cfg = {
state: {
// name: '',
@@ -885,17 +879,10 @@ async function main() {
name: 'CrowdNode Funding',
amount: 1.1,
status: DIALOG_STATUS.LOADING,
- // wallet,
- // contacts: appState.contacts,
- // submitTxt: `Fund your wallet`,
- // submitAlt: `Change the currently selected contact`,
- generateNextAddress: state => {
- // return html``
- return html`
- Send 1.1 Dash or more
- to signup & fund your CrowdNode account.
- `
- },
+ generateNextAddress: state => html`
+ Send 1.1 Dash or more
+ to signup & fund your CrowdNode account.
+ `,
footer: state => html`