mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-18 06:44:27 +01:00
styling pass
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@kobalte/core": "^0.8.2",
|
||||
"@kobalte/tailwindcss": "^0.5.0",
|
||||
"@motionone/solid": "^10.16.0",
|
||||
"@mutinywallet/node-manager": "^0.2.4",
|
||||
"@nostr-dev-kit/ndk": "^0.0.13",
|
||||
|
||||
42
pnpm-lock.yaml
generated
42
pnpm-lock.yaml
generated
@@ -4,6 +4,9 @@ dependencies:
|
||||
'@kobalte/core':
|
||||
specifier: ^0.8.2
|
||||
version: 0.8.2(solid-js@1.7.3)
|
||||
'@kobalte/tailwindcss':
|
||||
specifier: ^0.5.0
|
||||
version: 0.5.0(tailwindcss@3.3.1)
|
||||
'@motionone/solid':
|
||||
specifier: ^10.16.0
|
||||
version: 10.16.0(solid-js@1.7.3)
|
||||
@@ -1536,6 +1539,14 @@ packages:
|
||||
solid-js: 1.7.3
|
||||
dev: false
|
||||
|
||||
/@kobalte/tailwindcss@0.5.0(tailwindcss@3.3.1):
|
||||
resolution: {integrity: sha512-qP2C6mS4FcINHdUBFhNHe2QPvdSvbpDW30b0BgtPVu9F1H1nud2j3DJBezXMDE0N72mrxtvmLRyel9eIUCPVVQ==}
|
||||
peerDependencies:
|
||||
tailwindcss: ^3.2.7
|
||||
dependencies:
|
||||
tailwindcss: 3.3.1(postcss@8.4.21)
|
||||
dev: false
|
||||
|
||||
/@kobalte/utils@0.6.1(solid-js@1.7.3):
|
||||
resolution: {integrity: sha512-YvBqe9t9j0iYFUHfKXSMLQKM3s5+nL72RvT9b75W+IOxUpSpN4rdaI8C2j97k3LsEt7qY4ktJdt8lPM1rr8JXw==}
|
||||
peerDependencies:
|
||||
@@ -2255,7 +2266,6 @@ packages:
|
||||
|
||||
/any-promise@1.3.0:
|
||||
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
||||
dev: true
|
||||
|
||||
/anymatch@3.1.3:
|
||||
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||
@@ -2266,7 +2276,6 @@ packages:
|
||||
|
||||
/arg@5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
dev: true
|
||||
|
||||
/argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
@@ -2470,7 +2479,6 @@ packages:
|
||||
/camelcase-css@2.0.1:
|
||||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/caniuse-lite@1.0.30001478:
|
||||
resolution: {integrity: sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==}
|
||||
@@ -2546,7 +2554,6 @@ packages:
|
||||
/commander@4.1.1:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/common-tags@1.8.2:
|
||||
resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
|
||||
@@ -2615,7 +2622,6 @@ packages:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/csstype@2.6.21:
|
||||
resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
|
||||
@@ -2690,7 +2696,6 @@ packages:
|
||||
|
||||
/didyoumean@1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
dev: true
|
||||
|
||||
/dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
@@ -2700,7 +2705,6 @@ packages:
|
||||
|
||||
/dlv@1.1.3:
|
||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||
dev: true
|
||||
|
||||
/doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
@@ -3551,7 +3555,6 @@ packages:
|
||||
minimatch: 3.1.2
|
||||
once: 1.4.0
|
||||
path-is-absolute: 1.0.1
|
||||
dev: true
|
||||
|
||||
/glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
@@ -3891,7 +3894,6 @@ packages:
|
||||
/jiti@1.18.2:
|
||||
resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/joi@17.9.1:
|
||||
resolution: {integrity: sha512-FariIi9j6QODKATGBrEX7HZcja8Bsh3rfdGYy/Sb65sGlZWK/QWesU1ghk7aJWDj95knjXlQfSmzFSPPkLVsfw==}
|
||||
@@ -4000,11 +4002,9 @@ packages:
|
||||
/lilconfig@2.1.0:
|
||||
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
dev: true
|
||||
|
||||
/locate-path@6.0.0:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
@@ -4115,7 +4115,6 @@ packages:
|
||||
any-promise: 1.3.0
|
||||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
dev: true
|
||||
|
||||
/nanoid@3.3.6:
|
||||
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
|
||||
@@ -4180,12 +4179,10 @@ packages:
|
||||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/object-hash@3.0.0:
|
||||
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/object-inspect@1.12.3:
|
||||
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
|
||||
@@ -4299,12 +4296,10 @@ packages:
|
||||
/pify@2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/pirates@4.0.5:
|
||||
resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/polka@1.0.0-next.22:
|
||||
resolution: {integrity: sha512-a7tsZy5gFbJr0aUltZS97xCkbPglXuD67AMvTyZX7BTDBH384FWf0ZQF6rPvdutSxnO1vUlXM2zSLf5tCKk5RA==}
|
||||
@@ -4323,7 +4318,6 @@ packages:
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.2
|
||||
dev: true
|
||||
|
||||
/postcss-js@4.0.1(postcss@8.4.21):
|
||||
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
|
||||
@@ -4333,7 +4327,6 @@ packages:
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.21
|
||||
dev: true
|
||||
|
||||
/postcss-load-config@3.1.4(postcss@8.4.21):
|
||||
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
|
||||
@@ -4350,7 +4343,6 @@ packages:
|
||||
lilconfig: 2.1.0
|
||||
postcss: 8.4.21
|
||||
yaml: 1.10.2
|
||||
dev: true
|
||||
|
||||
/postcss-nested@6.0.0(postcss@8.4.21):
|
||||
resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==}
|
||||
@@ -4360,7 +4352,6 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.21
|
||||
postcss-selector-parser: 6.0.11
|
||||
dev: true
|
||||
|
||||
/postcss-selector-parser@6.0.11:
|
||||
resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==}
|
||||
@@ -4368,11 +4359,9 @@ packages:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
dev: true
|
||||
|
||||
/postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
dev: true
|
||||
|
||||
/postcss@8.4.21:
|
||||
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
|
||||
@@ -4429,7 +4418,6 @@ packages:
|
||||
/quick-lru@5.1.1:
|
||||
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
@@ -4441,7 +4429,6 @@ packages:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
dependencies:
|
||||
pify: 2.3.0
|
||||
dev: true
|
||||
|
||||
/readdirp@3.6.0:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
@@ -4918,7 +4905,6 @@ packages:
|
||||
mz: 2.7.0
|
||||
pirates: 4.0.5
|
||||
ts-interface-checker: 0.1.13
|
||||
dev: true
|
||||
|
||||
/supports-color@5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||
@@ -4969,7 +4955,6 @@ packages:
|
||||
sucrase: 3.32.0
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/temp-dir@2.0.0:
|
||||
resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
|
||||
@@ -5004,13 +4989,11 @@ packages:
|
||||
engines: {node: '>=0.8'}
|
||||
dependencies:
|
||||
thenify: 3.3.1
|
||||
dev: true
|
||||
|
||||
/thenify@3.3.1:
|
||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
dev: true
|
||||
|
||||
/to-fast-properties@2.0.0:
|
||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||
@@ -5040,7 +5023,6 @@ packages:
|
||||
|
||||
/ts-interface-checker@0.1.13:
|
||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||
dev: true
|
||||
|
||||
/tsconfig-paths@3.14.2:
|
||||
resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==}
|
||||
@@ -5199,7 +5181,6 @@ packages:
|
||||
|
||||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: true
|
||||
|
||||
/utils-merge@1.0.1:
|
||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||
@@ -5620,7 +5601,6 @@ packages:
|
||||
/yaml@1.10.2:
|
||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
|
||||
@@ -13,7 +13,8 @@ export function Amount(props: { amountSats: bigint | number | undefined, showFia
|
||||
const [state, _] = useMegaStore()
|
||||
|
||||
async function getPrice() {
|
||||
return await state.node_manager?.get_bitcoin_price()
|
||||
// return await state.node_manager?.get_bitcoin_price()
|
||||
return 30000
|
||||
}
|
||||
|
||||
const [price] = createResource(getPrice)
|
||||
|
||||
@@ -18,7 +18,7 @@ function SingleDigitButton(props: { character: string, onClick: (c: string) => v
|
||||
);
|
||||
}
|
||||
|
||||
export function AmountEditable(props: { amountSats: number | bigint, setAmountSats: (s: string) => void }) {
|
||||
export function AmountEditable(props: { amountSats: string, setAmountSats: (s: string) => void, onSave?: () => void }) {
|
||||
const [isFullscreen, setIsFullscreen] = createSignal(false);
|
||||
|
||||
function toggleFullscreen() {
|
||||
@@ -26,7 +26,7 @@ export function AmountEditable(props: { amountSats: number | bigint, setAmountSa
|
||||
}
|
||||
|
||||
// TODO: validate this doesn't need to be reactive and can be "initialAmountSats"
|
||||
const [displayAmount, setDisplayAmount] = createSignal(props.amountSats.toString() || "0");
|
||||
const [displayAmount, setDisplayAmount] = createSignal(props.amountSats || "0");
|
||||
|
||||
let inputRef!: HTMLInputElement;
|
||||
|
||||
@@ -113,7 +113,8 @@ export function AmountEditable(props: { amountSats: number | bigint, setAmountSa
|
||||
const [state, _] = useMegaStore()
|
||||
|
||||
async function getPrice() {
|
||||
return await state.node_manager?.get_bitcoin_price()
|
||||
// return await state.node_manager?.get_bitcoin_price()
|
||||
return 30000
|
||||
}
|
||||
|
||||
const [price] = createResource(getPrice)
|
||||
@@ -130,6 +131,10 @@ export function AmountEditable(props: { amountSats: number | bigint, setAmountSa
|
||||
} else {
|
||||
props.setAmountSats(displayAmount());
|
||||
toggleFullscreen();
|
||||
// This is so the parent can focus the next input if it wants to
|
||||
if (props.onSave) {
|
||||
props.onSave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ export function AmountInput(props: AmountInputProps) {
|
||||
const [state, _] = useMegaStore()
|
||||
|
||||
async function getPrice() {
|
||||
return await state.node_manager?.get_bitcoin_price()
|
||||
// return await state.node_manager?.get_bitcoin_price()
|
||||
return 30000
|
||||
}
|
||||
|
||||
const [activeCurrency, setActiveCurrency] = createSignal<ActiveCurrency>("sats")
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import logo from '~/assets/icons/mutiny-logo.svg';
|
||||
import { NodeManagerGuard, SafeArea } from "~/components/layout";
|
||||
import { DefaultMain, NodeManagerGuard, SafeArea } from "~/components/layout";
|
||||
import BalanceBox from "~/components/BalanceBox";
|
||||
import NavBar from "~/components/NavBar";
|
||||
|
||||
// TODO: use this reload prompt for real
|
||||
import ReloadPrompt from "~/components/Reload";
|
||||
import KitchenSink from './KitchenSink';
|
||||
import { Scan } from '~/assets/svg/Scan';
|
||||
import { A } from 'solid-start';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<NodeManagerGuard>
|
||||
<SafeArea>
|
||||
<main class='flex flex-col gap-4 py-8 px-4 max-w-[800px] mx-auto'>
|
||||
<header>
|
||||
<img src={logo} class="App-logo" alt="logo" />
|
||||
<DefaultMain>
|
||||
<header class="w-full flex justify-between items-center mt-4 mb-2">
|
||||
<img src={logo} class="h-10" alt="logo" />
|
||||
<A class="p-2 hover:bg-white/5 rounded-lg active:bg-m-blue" href="scanner"><Scan /></A>
|
||||
</header>
|
||||
<BalanceBox />
|
||||
<ReloadPrompt />
|
||||
<KitchenSink />
|
||||
{/* safety div */}
|
||||
<div class="h-32" />
|
||||
</main>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="home" />
|
||||
</SafeArea>
|
||||
</NodeManagerGuard>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createResource, Show, Suspense } from "solid-js";
|
||||
import { createResource, createSignal, Show, Suspense } from "solid-js";
|
||||
import { Button, ButtonLink, FancyCard } from "~/components/layout";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Amount } from "./Amount";
|
||||
@@ -10,46 +10,68 @@ function prettyPrintAmount(n?: number | bigint): string {
|
||||
return n.toLocaleString()
|
||||
}
|
||||
|
||||
function SyncingIndicator() {
|
||||
return (
|
||||
<div class="box-border animate-pulse px-2 py-1 -my-1 bg-white/70 rounded text-xs uppercase text-black">Syncing</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function BalanceBox() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
const fetchBalance = async () => {
|
||||
console.log("Refetching balance");
|
||||
const fetchOnchainBalance = async () => {
|
||||
console.log("Refetching onchain balance");
|
||||
await state.node_manager?.sync();
|
||||
const balance = await state.node_manager?.get_balance();
|
||||
return balance
|
||||
};
|
||||
|
||||
const [balance, { refetch: refetchBalance }] = createResource(fetchBalance);
|
||||
// TODO: it's hacky to do these separately, but ln doesn't need the sync so I don't want to wait
|
||||
const fetchLnBalance = async () => {
|
||||
console.log("Refetching ln balance");
|
||||
const balance = await state.node_manager?.get_balance();
|
||||
return balance
|
||||
};
|
||||
|
||||
const [onChainBalance, { refetch: refetchOnChainBalance }] = createResource(fetchOnchainBalance);
|
||||
const [lnBalance, { refetch: refetchLnBalance }] = createResource(fetchLnBalance);
|
||||
|
||||
function refetchBalance() {
|
||||
refetchLnBalance();
|
||||
refetchOnChainBalance();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FancyCard title="Lightning">
|
||||
<Suspense fallback={<Amount amountSats={0} showFiat loading={true} />}>
|
||||
<Amount amountSats={balance()?.lightning} showFiat loading={balance.loading} />
|
||||
<Show when={lnBalance()}>
|
||||
<Amount amountSats={lnBalance()?.lightning} showFiat />
|
||||
</Show>
|
||||
</Suspense>
|
||||
</FancyCard>
|
||||
<div class="flex gap-2 py-4">
|
||||
<ButtonLink href="/send" intent="green">Send</ButtonLink>
|
||||
<ButtonLink href="/receive" intent="blue">Receive</ButtonLink>
|
||||
</div>
|
||||
<FancyCard title="On-Chain">
|
||||
<FancyCard title="On-Chain" tag={onChainBalance.loading && <SyncingIndicator />}>
|
||||
<Suspense fallback={<Amount amountSats={0} showFiat loading={true} />}>
|
||||
<Amount amountSats={balance()?.confirmed} showFiat loading={balance.loading} />
|
||||
<div onClick={refetchBalance}>
|
||||
<Amount amountSats={onChainBalance()?.confirmed} showFiat loading={onChainBalance.loading} />
|
||||
</div>
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<Show when={balance()?.unconfirmed}>
|
||||
<Show when={onChainBalance()?.unconfirmed}>
|
||||
<div class="flex flex-col gap-2">
|
||||
<header class='text-sm font-semibold uppercase text-white/50'>
|
||||
Unconfirmed Balance
|
||||
</header>
|
||||
<div class="text-white/50">
|
||||
{prettyPrintAmount(balance()?.unconfirmed)} <span class='text-sm'>SATS</span>
|
||||
{prettyPrintAmount(onChainBalance()?.unconfirmed)} <span class='text-sm'>SATS</span>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</Suspense>
|
||||
<Button onClick={() => refetchBalance()}>Sync</Button>
|
||||
</FancyCard>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mutiny_m from '~/assets/icons/m.svg';
|
||||
import scan from '~/assets/icons/scan.svg';
|
||||
// import scan from '~/assets/icons/scan.svg';
|
||||
import airplane from '~/assets/icons/airplane.svg';
|
||||
import settings from '~/assets/icons/settings.svg';
|
||||
|
||||
@@ -8,21 +8,16 @@ import { A } from "solid-start";
|
||||
type ActiveTab = 'home' | 'scan' | 'send' | 'settings' | 'none';
|
||||
|
||||
export default function NavBar(props: { activeTab: ActiveTab }) {
|
||||
const activeStyle = 'h-full border-t-2 border-b-2 border-b-sidebar-gray flex flex-col justify-center md:border-t-0 md:border-b-0 md:p-2 md:bg-white/20 md:rounded-xl'
|
||||
const inactiveStyle = "md:p-2 md:hover:bg-white/10 md:rounded-xl"
|
||||
const activeStyle = 'h-full border-t-2 border-b-2 border-b-sidebar-gray flex flex-col justify-center md:border-t-0 md:border-b-0 md:p-2 md:bg-black md:rounded-lg'
|
||||
const inactiveStyle = "md:p-2 md:hover:bg-white/5 md:rounded-lg md:active:bg-m-blue"
|
||||
return (
|
||||
<nav class='bg-sidebar-gray fixed bottom-0 shadow-lg z-40 w-full safe-bottom md:top-0 md:bottom-auto md:left-0 md:w-auto md:h-full'>
|
||||
<nav class='backdrop-blur-xl fixed bottom-0 md:shadow-none shadow-above z-40 w-full safe-bottom md:top-0 md:bottom-auto md:left-0 md:w-auto md:h-full'>
|
||||
<ul class='h-16 flex justify-between px-16 items-center md:flex-col md:justify-start md:gap-4 md:px-4 md:mt-4'>
|
||||
<li class={props.activeTab === "home" ? activeStyle : inactiveStyle}>
|
||||
<A href="/">
|
||||
<img src={mutiny_m} alt="home" />
|
||||
</A>
|
||||
</li>
|
||||
<li class={props.activeTab === "scan" ? activeStyle : inactiveStyle}>
|
||||
<A href="/scanner">
|
||||
<img src={scan} alt="scan" />
|
||||
</A>
|
||||
</li>
|
||||
<li class={props.activeTab === "send" ? activeStyle : inactiveStyle}>
|
||||
<A href="/send">
|
||||
<img src={airplane} alt="send" />
|
||||
|
||||
@@ -3,12 +3,13 @@ import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import { A } from "solid-start";
|
||||
|
||||
const button = cva("p-4 rounded-xl text-xl font-semibold disabled:opacity-50 disabled:grayscale transition", {
|
||||
const button = cva("p-3 rounded-xl text-xl font-semibold disabled:opacity-50 disabled:grayscale transition", {
|
||||
variants: {
|
||||
// TODO: button hover has to work different than buttonlinks (like disabled state)
|
||||
intent: {
|
||||
active: "bg-white text-black border border-white hover:text-[#3B6CCC]",
|
||||
inactive: "bg-black text-white border border-white hover:text-[#3B6CCC]",
|
||||
glowy: "bg-black/10 shadow-xl text-white border border-m-blue hover:m-blue-dark hover:text-m-blue",
|
||||
blue: "bg-m-blue text-white shadow-inner-button hover:bg-m-blue-dark text-shadow-button",
|
||||
red: "bg-m-red text-white shadow-inner-button hover:bg-m-red-dark text-shadow-button",
|
||||
green: "bg-m-green text-white shadow-inner-button hover:bg-m-green-dark text-shadow-button",
|
||||
@@ -17,6 +18,7 @@ const button = cva("p-4 rounded-xl text-xl font-semibold disabled:opacity-50 dis
|
||||
flex: "flex-1",
|
||||
pad: "px-8",
|
||||
small: "px-4 py-2 w-auto text-lg",
|
||||
xs: "px-2 py-1 w-auto rounded-lg font-normal text-base"
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
30
src/components/layout/Radio.tsx
Normal file
30
src/components/layout/Radio.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { RadioGroup } from "@kobalte/core";
|
||||
import { For } from "solid-js";
|
||||
|
||||
type Choices = { value: string, label: string, caption: string }[]
|
||||
|
||||
// TODO: how could would it be if we could just pass the estimated fees in here?
|
||||
export function StyledRadioGroup(props: { value: string, choices: Choices, onValueChange: (value: string) => void }) {
|
||||
return (
|
||||
<RadioGroup.Root value={props.value} onValueChange={(e) => props.onValueChange(e)} class="grid w-full gap-4 grid-cols-2">
|
||||
<For each={props.choices}>
|
||||
{choice =>
|
||||
<RadioGroup.Item value={choice.value} class="ui-checked:bg-white bg-white/10 rounded outline outline-black/50 ui-checked:outline-m-blue ui-checked:outline-2">
|
||||
<div class="py-3 px-4">
|
||||
<RadioGroup.ItemInput class="radio__input " />
|
||||
<RadioGroup.ItemControl class="radio__control">
|
||||
<RadioGroup.ItemIndicator class="radio__indicator" />
|
||||
</RadioGroup.ItemControl>
|
||||
<RadioGroup.ItemLabel class="ui-checked:text-m-blue text-neutral-400">
|
||||
<div class="block">
|
||||
<div class="text-lg font-semibold">{choice.label}</div>
|
||||
<div class="text-lg font-light">{choice.caption}</div>
|
||||
</div>
|
||||
</RadioGroup.ItemLabel>
|
||||
</div>
|
||||
</RadioGroup.Item>
|
||||
}
|
||||
</For>
|
||||
</RadioGroup.Root>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ParentComponent, Show, Suspense } from "solid-js"
|
||||
import { JSX, ParentComponent, Show, Suspense } from "solid-js"
|
||||
import Linkify from "./Linkify"
|
||||
import { Button, ButtonLink } from "./Button"
|
||||
import { Separator } from "@kobalte/core"
|
||||
@@ -8,7 +8,7 @@ const SmallHeader: ParentComponent = (props) => <header class='text-sm font-semi
|
||||
|
||||
const Card: ParentComponent<{ title?: string }> = (props) => {
|
||||
return (
|
||||
<div class='rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]'>
|
||||
<div class='rounded-xl p-4 flex flex-col gap-2 bg-neutral-800'>
|
||||
{props.title && <SmallHeader>{props.title}</SmallHeader>}
|
||||
{props.children}
|
||||
</div>
|
||||
@@ -24,26 +24,34 @@ const InnerCard: ParentComponent<{ title?: string }> = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const FancyCard: ParentComponent<{ title?: string }> = (props) => {
|
||||
const FancyCard: ParentComponent<{ title?: string, tag?: JSX.Element }> = (props) => {
|
||||
return (
|
||||
<div class='border border-white rounded-xl border-b-4 p-4 flex flex-col gap-2'>
|
||||
<div class='border border-black/50 rounded-xl border-b-4 p-4 flex flex-col gap-2 bg-neutral-800/50 shadow-fancy-card'>
|
||||
<div class="w-full flex justify-between items-center">
|
||||
{props.title && <SmallHeader>{props.title}</SmallHeader>}
|
||||
{props.tag && props.tag}
|
||||
</div>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SafeArea: ParentComponent<{ main?: boolean }> = (props) => {
|
||||
const SafeArea: ParentComponent = (props) => {
|
||||
return (
|
||||
<div class="safe-top safe-left safe-right safe-bottom">
|
||||
<div class="disable-scrollbars max-h-screen h-full overflow-y-scroll md:pl-[8rem] md:pr-[6rem]">
|
||||
<Show when={props.main} fallback={props.children}>
|
||||
<main class='flex flex-col py-8 px-4 items-center'>
|
||||
{props.children}
|
||||
<div class="h-32" />
|
||||
</div>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
const DefaultMain: ParentComponent = (props) => {
|
||||
return (
|
||||
<main class="w-full max-w-[600px] flex flex-col gap-4 mx-auto p-4">
|
||||
{props.children}
|
||||
</main>
|
||||
</Show>
|
||||
</div>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
@@ -78,4 +86,8 @@ const LoadingSpinner = () => {
|
||||
|
||||
const Hr = () => <Separator.Root class="my-4 border-white/20" />
|
||||
|
||||
export { SmallHeader, Card, SafeArea, LoadingSpinner, Button, ButtonLink, Linkify, Hr, NodeManagerGuard, FullscreenLoader, InnerCard, FancyCard }
|
||||
const LargeHeader: ParentComponent = (props) => {
|
||||
return (<h1 class="text-4xl font-semibold uppercase border-b-2 border-b-white my-4">{props.children}</h1>)
|
||||
}
|
||||
|
||||
export { SmallHeader, Card, SafeArea, LoadingSpinner, Button, ButtonLink, Linkify, Hr, NodeManagerGuard, FullscreenLoader, InnerCard, FancyCard, DefaultMain, LargeHeader }
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
@apply text-white bg-black;
|
||||
@apply bg-fixed bg-no-repeat bg-fade-to-blue;
|
||||
@apply text-white bg-neutral-900;
|
||||
overscroll-behavior-y: none;
|
||||
min-height: 100.3%;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { TextField } from "@kobalte/core";
|
||||
import { createMemo, createResource, createSignal, Match, Switch } from "solid-js";
|
||||
import { QRCodeSVG } from "solid-qr-code";
|
||||
import { AmountEditable } from "~/components/AmountEditable";
|
||||
import { AmountInput } from "~/components/AmountInput";
|
||||
import { Button, Card, NodeManagerGuard, SafeArea, SmallHeader } from "~/components/layout";
|
||||
import { Button, Card, DefaultMain, LargeHeader, NodeManagerGuard, SafeArea, SmallHeader } from "~/components/layout";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { satsToUsd } from "~/utils/conversions";
|
||||
@@ -83,36 +84,44 @@ export default function Receive() {
|
||||
}
|
||||
|
||||
async function getPrice() {
|
||||
return await state.node_manager?.get_bitcoin_price()
|
||||
// return await state.node_manager?.get_bitcoin_price()
|
||||
return 30000
|
||||
}
|
||||
|
||||
const [price] = createResource(getPrice)
|
||||
|
||||
const amountInUsd = createMemo(() => satsToUsd(price(), parseInt(amount()) || 0, true))
|
||||
|
||||
function handleAmountSave() {
|
||||
console.error("focusing label input...")
|
||||
console.error(labelInput)
|
||||
labelInput.focus();
|
||||
}
|
||||
|
||||
return (
|
||||
<NodeManagerGuard>
|
||||
|
||||
<SafeArea main>
|
||||
<div class="w-full max-w-[400px] flex flex-col gap-4">
|
||||
<h1 class="text-2xl font-semibold uppercase border-b-2 border-b-white">Receive Bitcoin</h1>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<LargeHeader>Receive Bitcoin</LargeHeader>
|
||||
<Switch>
|
||||
<Match when={!unified() || receiveState() === "edit"}>
|
||||
<form class="border border-white/20 rounded-xl p-2 flex flex-col gap-4" onSubmit={onSubmit} >
|
||||
{/* TODO this initial amount is not reactive, hope that's okay? */}
|
||||
<AmountInput initialAmountSats={amount()} setAmountSats={setAmount} refSetter={el => amountInput = el} />
|
||||
<AmountEditable amountSats={amount() || "0"} setAmountSats={setAmount} onSave={handleAmountSave} />
|
||||
<div>
|
||||
<Button intent="glowy" layout="xs">Tag the sender</Button>
|
||||
</div>
|
||||
<form class="flex flex-col gap-4" onSubmit={onSubmit} >
|
||||
<TextField.Root
|
||||
value={label()}
|
||||
onValueChange={setLabel}
|
||||
class="flex flex-col gap-2"
|
||||
>
|
||||
<TextField.Label class="text-sm font-semibold uppercase" >Label (private)</TextField.Label>
|
||||
<TextField.Label><SmallHeader>Label (private)</SmallHeader></TextField.Label>
|
||||
<TextField.Input
|
||||
autofocus
|
||||
ref={el => labelInput = el}
|
||||
class="w-full p-2 rounded-lg text-black" />
|
||||
</TextField.Root>
|
||||
<Button disabled={!amount() || !label()} layout="small" type="submit">Create Invoice</Button>
|
||||
<Button disabled={!amount() || !label()} intent="green" type="submit">Create Invoice</Button>
|
||||
</form >
|
||||
</Match>
|
||||
<Match when={unified() && receiveState() === "show"}>
|
||||
@@ -139,7 +148,7 @@ export default function Receive() {
|
||||
</Card>
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="none" />
|
||||
</SafeArea >
|
||||
</NodeManagerGuard>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TextField } from "@kobalte/core";
|
||||
import { Show, createResource, createSignal, onMount } from "solid-js";
|
||||
import { RadioGroup, TextField } from "@kobalte/core";
|
||||
import { For, Show, createResource, createSignal, onMount } from "solid-js";
|
||||
import { Amount } from "~/components/Amount";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { Button, ButtonLink, InnerCard, SafeArea, SmallHeader } from "~/components/layout";
|
||||
import { Button, ButtonLink, DefaultMain, FancyCard, InnerCard, LargeHeader, SafeArea, SmallHeader } from "~/components/layout";
|
||||
import { Paste } from "~/assets/svg/Paste";
|
||||
import { Scan } from "~/assets/svg/Scan";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
@@ -10,9 +10,12 @@ import { MutinyInvoice, NodeManager } from "@mutinywallet/node-manager";
|
||||
import { bip21decode } from "~/utils/TEMPbip21";
|
||||
import { AmountEditable } from "~/components/AmountEditable";
|
||||
import { useLocation } from "solid-start";
|
||||
import { StyledRadioGroup } from "~/components/layout/Radio";
|
||||
|
||||
type SendSource = "lightning" | "onchain";
|
||||
|
||||
const PAYMENT_METHODS = [{ value: "lightning", label: "Lightning", caption: "Fast and cool" }, { value: "onchain", label: "On-chain", caption: "Just like Satoshi did it" }]
|
||||
|
||||
export default function Send() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
@@ -118,15 +121,15 @@ export default function Send() {
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeArea main>
|
||||
<div class="w-full max-w-[400px] flex flex-col gap-4">
|
||||
<h1 class="text-2xl font-semibold uppercase border-b-2 border-b-white">Send Bitcoin</h1>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<LargeHeader>Send Bitcoin</LargeHeader>
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
<SmallHeader>Destination</SmallHeader>
|
||||
</dt>
|
||||
<dd>
|
||||
<InnerCard>
|
||||
<Show when={destination()} fallback={<div class="flex flex-row gap-4">
|
||||
<Button onClick={handlePaste}>
|
||||
<div class="flex flex-col gap-2 items-center">
|
||||
@@ -141,23 +144,32 @@ export default function Send() {
|
||||
</div>
|
||||
</ButtonLink>
|
||||
</div>}>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Show when={address()}>
|
||||
<code class="line-clamp-3 text-sm break-all">{source() === "onchain" && "→"} {address()}</code>
|
||||
|
||||
<div class="flex gap-2 items-center">
|
||||
<Show when={address() && source() === "onchain"}>
|
||||
<code class="truncate text-sm break-all">{"Address: "} {address()}
|
||||
<Show when={description()}>
|
||||
<br />
|
||||
{"Description:"} {description()}
|
||||
</Show>
|
||||
<Show when={invoice()}>
|
||||
<code class="line-clamp-3 text-sm break-all">{source() === "lightning" && "→"} {invoice()?.bolt11}</code>
|
||||
</code>
|
||||
</Show>
|
||||
|
||||
<Show when={invoice() && source() === "lightning"}>
|
||||
<code class="truncate text-sm break-all">{"Invoice: "} {invoice()?.bolt11}
|
||||
<Show when={description()}>
|
||||
<br />
|
||||
{"Description:"} {description()}
|
||||
</Show>
|
||||
</code>
|
||||
</Show>
|
||||
<Button class="flex-0" intent="glowy" layout="xs" onClick={clearAll}>Clear</Button>
|
||||
</div>
|
||||
{/* <code class="line-clamp-3 text-sm break-all mb-2">{destination()}</code> */}
|
||||
<Show when={destination()}>
|
||||
<Button intent="inactive" onClick={clearAll}>Clear</Button>
|
||||
<div class="my-4">
|
||||
{/* if the amount came with the invoice we can't allow setting it */}
|
||||
<Show when={!(invoice()?.amount_sats)} fallback={<Amount amountSats={amountSats() || 0} showFiat />}>
|
||||
<AmountEditable amountSats={amountSats().toString() || "0"} setAmountSats={setAmountSats} />
|
||||
</Show>
|
||||
|
||||
</div>
|
||||
</Show>
|
||||
</InnerCard>
|
||||
</dd>
|
||||
|
||||
<Show when={address() && invoice()}>
|
||||
@@ -167,38 +179,9 @@ export default function Send() {
|
||||
</SmallHeader>
|
||||
</dt>
|
||||
<dd>
|
||||
<div class="flex gap-4 items-start">
|
||||
<Button onClick={() => setSource("lightning")} intent={source() === "lightning" ? "active" : "inactive"} layout="small">Lightning</Button>
|
||||
<Button onClick={() => setSource("onchain")} intent={source() === "onchain" ? "active" : "inactive"} layout="small">On-Chain</Button>
|
||||
</div>
|
||||
<StyledRadioGroup value={source()} onValueChange={setSource} choices={PAYMENT_METHODS} />
|
||||
</dd>
|
||||
</Show>
|
||||
<Show when={destination()}>
|
||||
<dt>
|
||||
<SmallHeader>
|
||||
Amount
|
||||
</SmallHeader>
|
||||
</dt>
|
||||
<dd>
|
||||
{/* if the amount came with the invoice we can't allow setting it */}
|
||||
<Show when={!(invoice()?.amount_sats)} fallback={<Amount amountSats={amountSats() || 0} showFiat />}>
|
||||
<AmountEditable amountSats={amountSats() || 0} setAmountSats={setAmountSats} />
|
||||
</Show>
|
||||
</dd>
|
||||
</Show>
|
||||
|
||||
|
||||
<Show when={description()}>
|
||||
<dt>
|
||||
|
||||
<SmallHeader>Description</SmallHeader>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<code class="line-clamp-3 text-sm break-all">{description()}</code>
|
||||
</dd>
|
||||
</Show>
|
||||
|
||||
<Show when={destination()}>
|
||||
<TextField.Root
|
||||
value={privateLabel()}
|
||||
@@ -214,7 +197,7 @@ export default function Send() {
|
||||
<TextField.Input
|
||||
autofocus
|
||||
ref={el => labelInput = el}
|
||||
class="w-full p-2 rounded-lg text-black"
|
||||
class="w-full p-2 rounded-lg bg-white/10"
|
||||
placeholder="A helpful reminder of why you spent bitcoin"
|
||||
/>
|
||||
</dd>
|
||||
@@ -222,9 +205,7 @@ export default function Send() {
|
||||
</Show>
|
||||
</dl>
|
||||
<Button disabled={!destination()} intent="blue" onClick={handleSend}>Confirm Send</Button>
|
||||
</div>
|
||||
{/* safety div */}
|
||||
<div class="h-32" />
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="send" />
|
||||
</SafeArea >
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useNavigate } from "solid-start";
|
||||
import { Button, SafeArea } from "~/components/layout";
|
||||
import KitchenSink from "~/components/KitchenSink";
|
||||
import { Button, Card, DefaultMain, Hr, LargeHeader, SafeArea } from "~/components/layout";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
|
||||
@@ -31,11 +32,16 @@ export default function Settings() {
|
||||
|
||||
return (
|
||||
<SafeArea>
|
||||
<main class='flex flex-col gap-4 py-8 px-4 max-w-[800px] mx-auto'>
|
||||
<DefaultMain>
|
||||
<LargeHeader>Settings</LargeHeader>
|
||||
<Card title="Random utilities">
|
||||
<Button onClick={clearWaitlistId}>Clear waitlist_id</Button>
|
||||
<Button onClick={setTestWaitlistId}>Use test waitlist_id</Button>
|
||||
<Button onClick={resetNode}>Reset node</Button>
|
||||
</main>
|
||||
</Card>
|
||||
<Hr />
|
||||
<KitchenSink />
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
)
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { Title } from "solid-start";
|
||||
import { HttpStatusCode } from "solid-start/server";
|
||||
import { ButtonLink, DefaultMain, LargeHeader, SafeArea } from "~/components/layout";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<main>
|
||||
<SafeArea>
|
||||
|
||||
<Title>Not Found</Title>
|
||||
<HttpStatusCode code={404} />
|
||||
<h1>Page Not Found</h1>
|
||||
<DefaultMain>
|
||||
<LargeHeader>Not Found</LargeHeader>
|
||||
<p>
|
||||
Visit{" "}
|
||||
<a href="https://start.solidjs.com" target="_blank">
|
||||
start.solidjs.com
|
||||
</a>{" "}
|
||||
to learn how to build SolidStart apps.
|
||||
This is probably Paul's fault.
|
||||
</p>
|
||||
</main>
|
||||
<div class="h-full">
|
||||
|
||||
</div>
|
||||
<ButtonLink href="/" intent="red">Dangit</ButtonLink>
|
||||
</DefaultMain>
|
||||
</SafeArea>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,17 +32,20 @@ module.exports = {
|
||||
},
|
||||
dropShadow: {
|
||||
'blue-glow': '0px 0px 32px rgba(11, 33, 91, 0.5)',
|
||||
'inner-button': '2px 2px 4px rgba(0, 0, 0, 0.1), inset 2px 2px 4px rgba(255, 255, 255, 0.25), inset -2px -2px 6px rgba(0, 0, 0, 0.3);'
|
||||
},
|
||||
boxShadow: {
|
||||
'inner-button': '2px 2px 4px rgba(0, 0, 0, 0.1), inset 2px 2px 4px rgba(255, 255, 255, 0.25), inset -2px -2px 6px rgba(0, 0, 0, 0.3);'
|
||||
'inner-button': '2px 2px 4px rgba(0, 0, 0, 0.1), inset 2px 2px 4px rgba(255, 255, 255, 0.1), inset -2px -2px 6px rgba(0, 0, 0, 0.2)',
|
||||
'fancy-card': '0px 4px 4px rgba(0, 0, 0, 0.1)',
|
||||
'above': '0px -4px 10px rgba(0, 0, 0, 0.25)',
|
||||
},
|
||||
textShadow: {
|
||||
'button': '1px 1px 0px rgba(0, 0, 0, 0.4);'
|
||||
'button': '1px 1px 0px rgba(0, 0, 0, 0.4)'
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
// default prefix is "ui"
|
||||
require("@kobalte/tailwindcss"),
|
||||
plugin(function ({ addUtilities }) {
|
||||
const newUtilities = {
|
||||
'.safe-top': {
|
||||
|
||||
Reference in New Issue
Block a user