]> zoso.dev Git - nemo-wallet.git/commitdiff
To avoid selector bugs caused by the difference in parameters between getElementById...
authorChris Duncan <chris@zoso.dev>
Sat, 19 Oct 2024 08:51:05 +0000 (01:51 -0700)
committerChris Duncan <chris@zoso.dev>
Sat, 19 Oct 2024 08:51:05 +0000 (01:51 -0700)
app/pages/nemo-wallet.html

index 5811a465497dcef6d5fa5f4398094eed8ec90667..ff966a4d99517bcbbafbabe2b15481ba390f0312 100644 (file)
 <!DOCTYPE html>
 
 <head>
-  <meta lang="en" />
-  <meta name="viewport" content="width=device-width, initial-scale=1" />
-  <script>
-    let Account, Bip44Wallet, Blake2bWallet, LedgerWallet, SendBlock, ReceiveBlock, ChangeBlock, rpc, Rolodex, Xel
-    const observer = new MutationObserver((mutations) => {
-      for (const mutation of mutations) {
-        if (mutation.type === "attributes") {
-          mutation.target.dispatchEvent(new Event('attributeschanged'))
-        }
-      }
-    })
-    function load () {
-      loadUi().then(loadNemo).then(loadUx).then(() => { console.log('done') })
-    }
-    async function loadUi () {
-      console.log('loading xel')
-      Xel = await import('https://unpkg.com/xel@latest')
-      await Xel.whenThemeReady
-      setTimeout(() => {
-        document.getElementsByTagName('body')[0].style.visibility = 'visible'
-      }, 250)
-      console.log('loaded xel')
-    }
-    async function loadNemo () {
-      console.log('loading libnemo')
-      await ({ Account, Bip44Wallet, Blake2bWallet, LedgerWallet, SendBlock, ReceiveBlock, ChangeBlock, Node: rpc, Rolodex } = await import('https://unpkg.com/libnemo@latest'))
-      console.log('loaded libnemo')
-    }
-    async function loadUx () {
-      if (location.hash) {
-        const page = document.querySelector(location.hash)
-        page.classList.add('show')
-      } else {
-        location += '#transact'
-      }
-    }
-    function switchPage (evt) {
-      console.log(evt)
-      const oldHash = new URL(evt.oldURL)?.hash
-      const newHash = new URL(evt.newURL)?.hash
-      if (oldHash) {
-        document.querySelector(oldHash).classList.remove('show')
-      }
-      if (newHash) {
-        document.querySelector(newHash).classList.add('show')
-      }
-    }
-    function getWalletType (type) {
-      switch (type) {
-        case 'blake2b': {
-          return Blake2bWallet
-        }
-        case 'bip44':
-        default: {
-          return Bip44Wallet
-        }
-      }
-    }
+       <meta lang="en" />
+       <meta name="viewport" content="width=device-width, initial-scale=1" />
+       <script>
+               let Account, Bip44Wallet, Blake2bWallet, LedgerWallet, SendBlock, ReceiveBlock, ChangeBlock, rpc, Rolodex, Xel
+               const observer = new MutationObserver((mutations) => {
+                       for (const mutation of mutations) {
+                               if (mutation.type === "attributes") {
+                                       mutation.target.dispatchEvent(new Event('attributeschanged'))
+                               }
+                       }
+               })
+               function load () {
+                       loadUi().then(loadNemo).then(loadUx).then(() => { console.log('done') })
+               }
+               async function loadUi () {
+                       console.log('loading xel')
+                       Xel = await import('https://unpkg.com/xel@latest')
+                       await Xel.whenThemeReady
+                       setTimeout(() => {
+                               document.getElementsByTagName('body')[0].style.visibility = 'visible'
+                       }, 250)
+                       console.log('loaded xel')
+               }
+               async function loadNemo () {
+                       console.log('loading libnemo')
+                       await ({ Account, Bip44Wallet, Blake2bWallet, LedgerWallet, SendBlock, ReceiveBlock, ChangeBlock, Node: rpc, Rolodex } = await import('https://unpkg.com/libnemo@latest'))
+                       console.log('loaded libnemo')
+               }
+               async function loadUx () {
+                       if (location.hash) {
+                               const page = document.querySelector(location.hash)
+                               page.classList.add('show')
+                       } else {
+                               location += '#transact'
+                       }
+               }
+               function switchPage (evt) {
+                       console.log(evt)
+                       const oldHash = new URL(evt.oldURL)?.hash
+                       const newHash = new URL(evt.newURL)?.hash
+                       if (oldHash) {
+                               document.querySelector(oldHash).classList.remove('show')
+                       }
+                       if (newHash) {
+                               document.querySelector(newHash).classList.add('show')
+                       }
+               }
+               function getWalletType (type) {
+                       switch (type) {
+                               case 'blake2b': {
+                                       return Blake2bWallet
+                               }
+                               case 'bip44':
+                               default: {
+                                       return Bip44Wallet
+                               }
+                       }
+               }
 
-    async function updateWallet () {
-      const wallet = document.getElementById('wallet').value
-      if (wallet !== '_new' && wallet !== '_import' && wallet !== '_ledger') {
-        return await updateAccount()
-      }
-      if (wallet === '_ledger') {
-        return await LedgerWallet.create()
-      }
-      const form = document.getElementById('wallet-form')
-      const walletType = document.getElementById('wallet-form-wallet-type')
-      const importType = document.getElementById('wallet-form-import-type')
-      const importValue = document.getElementById('wallet-form-import-value')
-      const salt = document.getElementById('wallet-form-salt')
-      walletType.querySelector('x-radios').value = null
-      importType.querySelector('x-select').value = null
-      importValue.querySelector('x-input').value = null
-      salt.querySelector('x-input').value = null
-      if (wallet.value === '_new') {
-        importType.classList.add('hide')
-        importValue.classList.add('hide')
-        salt.classList.remove('hide')
-      }
-      if (wallet.value === '_import') {
-        importType.classList.remove('hide')
-        importValue.classList.remove('hide')
-        salt.classList.add('hide')
-      }
-      return await form.showModal()
-    }
+               async function updateWallet () {
+                       const wallet = document.querySelector('#wallet').value
+                       if (wallet !== '_new' && wallet !== '_import' && wallet !== '_ledger') {
+                               return await updateAccount()
+                       }
+                       if (wallet === '_ledger') {
+                               return await LedgerWallet.create()
+                       }
+                       const form = document.querySelector('#wallet-form')
+                       const walletType = document.querySelector('#wallet-form-wallet-type')
+                       const importType = document.querySelector('#wallet-form-import-type')
+                       const importValue = document.querySelector('#wallet-form-import-value')
+                       const salt = document.querySelector('#wallet-form-salt')
+                       walletType.querySelector('x-radios').value = null
+                       importType.querySelector('x-select').value = null
+                       importValue.querySelector('x-input').value = null
+                       salt.querySelector('x-input').value = null
+                       if (wallet.value === '_new') {
+                               importType.classList.add('hide')
+                               importValue.classList.add('hide')
+                               salt.classList.remove('hide')
+                       }
+                       if (wallet.value === '_import') {
+                               importType.classList.remove('hide')
+                               importValue.classList.remove('hide')
+                               salt.classList.add('hide')
+                       }
+                       return await form.showModal()
+               }
 
-    function spinner (btn) {
-      const label = btn.firstElementChild
-      const spinner = document.createElement('x-throbber')
-      spinner.size = 'small'
-      spinner.style.width = `${label.scrollWidth}px`
-      btn.replaceChildren(spinner)
-      // at some point then...
-      // btn.replaceChildren(label)
-    }
+               function spinner (btn) {
+                       const label = btn.firstElementChild
+                       const spinner = document.createElement('x-throbber')
+                       spinner.size = 'small'
+                       spinner.style.width = `${label.scrollWidth}px`
+                       btn.replaceChildren(spinner)
+                       // at some point then...
+                       // btn.replaceChildren(label)
+               }
 
-    async function createWallet () {
-      const walletSelect = document.getElementById('wallet')
-      const form = document.getElementById('wallet-form')
-      const name = form.querySelector('#wallet-form-name x-input').value
-      if (name === '_new' || name === '_import' || name === '_ledger') {
-        walletSelect.value = null
-        notify.warn(`Invalid wallet name "${name}".`)
-        return
-      }
-      const type = form.querySelector('#wallet-form-wallet-type x-radios').value
-      const walletType = getWalletType(type)
-      const salt = form.querySelector('#wallet-form-salt x-input')?.value
-      const password = form.querySelector('#wallet-form-password x-input')?.value
-      if (!password) {
-        walletSelect.value = null
-        notify.error('Password is required')
-        return
-      }
-      let wallet
-      try {
-        wallet = await walletType.create(password, salt)
-        const walletData = {
-          id: wallet.id,
-          name: name || wallet.id,
-          type
-        }
-        await addToStorage(`wallets`, JSON.stringify(walletData))
+               async function createWallet () {
+                       const walletSelect = document.querySelector('#wallet')
+                       const form = document.querySelector('#wallet-form')
+                       const name = form.querySelector('#wallet-form-name x-input').value
+                       if (name === '_new' || name === '_import' || name === '_ledger') {
+                               walletSelect.value = null
+                               notify.warn(`Invalid wallet name "${name}".`)
+                               return
+                       }
+                       const type = form.querySelector('#wallet-form-wallet-type x-radios').value
+                       const walletType = getWalletType(type)
+                       const salt = form.querySelector('#wallet-form-salt x-input')?.value
+                       const password = form.querySelector('#wallet-form-password x-input')?.value
+                       if (!password) {
+                               walletSelect.value = null
+                               notify.error('Password is required')
+                               return
+                       }
+                       let wallet
+                       try {
+                               wallet = await walletType.create(password, salt)
+                               const walletData = {
+                                       id: wallet.id,
+                                       name: name || wallet.id,
+                                       type
+                               }
+                               await addToStorage(`wallets`, JSON.stringify(walletData))
 
-        const menu = document.querySelector('#wallet > x-menu')
-        const menuitem = document.createElement('x-menuitem')
-        menuitem.value = walletData.id
-        if (menu.childElementCount >= 0) {
-          menu.appendChild(menuitem)
-        }
-        const label = document.createElement('x-label')
-        label.innerText = walletData.name
-        menuitem.appendChild(label)
-        walletSelect.value = walletData.id
-      } catch (err) {
-        label?.remove()
-        menuitem?.remove()
-        walletSelect.value = null
-        notify.error(err.msg)
-      } finally {
-        await form.close()
-        return wallet
-      }
-    }
+                               const menu = document.querySelector('#wallet > x-menu')
+                               const menuitem = document.createElement('x-menuitem')
+                               menuitem.value = walletData.id
+                               if (menu.childElementCount >= 0) {
+                                       menu.appendChild(menuitem)
+                               }
+                               const label = document.createElement('x-label')
+                               label.innerText = walletData.name
+                               menuitem.appendChild(label)
+                               walletSelect.value = walletData.id
+                       } catch (err) {
+                               label?.remove()
+                               menuitem?.remove()
+                               walletSelect.value = null
+                               notify.error(err.msg)
+                       } finally {
+                               await form.close()
+                               return wallet
+                       }
+               }
 
-    function addToStorage (key, value) {
-      if (typeof value !== 'string') {
-        throw new TypeError(`Cannot add ${typeof value} to storage`)
-      }
-      const item = JSON.parse(sessionStorage.getItem(key) ?? '[]')
-      if (!Array.isArray(item)) {
-        throw new TypeError(`Storage item is not an array`)
-      }
-      item.push(value)
-      return new Promise((resolve, reject) => {
-        try {
-          sessionStorage.setItem(key, JSON.stringify(item))
-          resolve()
-        } catch (err) {
-          console.error(err)
-          reject(err)
-        }
-      })
-    }
-    function updateWalletForm () {
-      const form = document.getElementById('wallet-form')
-      const walletTypeContainer = document.getElementById('wallet-form-wallet-type')
-      const walletType = walletTypeContainer.firstChild
-      const importTypeContainer = document.getElementById('wallet-form-import-type')
-      const importType = importTypeContainer.firstChild
-      const saltContainer = document.getElementById('wallet-form-salt')
-      if (walletType.value === 'bip44' && importType.value === 'mnemonic') {
-        saltContainer.classList.remove('hide')
-      } else {
-        saltContainer.classList.add('hide')
-      }
-      document.querySelector('#wallet-form-import-value x-label').innerText = importType.value
-    }
-    async function showWallets () {
-      const card = document.getElementById('walletCard')
-      const storedWalletData = JSON.parse(sessionStorage.getItem('wallets') ?? '[]')
-      const wallets = []
-      for (const walletData of storedWalletData) {
-        const w = JSON.parse(walletData)
-        console.dir(w)
-        if (w.id && w.name && w.type) {
-          const walletType = getWalletType(w.type)
-          wallets.push(await walletType.restore(w.id))
-        }
-      }
-      const walletElements = []
-      for (const wallet of wallets) {
-        const walletElement = document.createElement('x-label')
-        await wallet.unlock('password')
-        walletElement.innerText = `${wallet.name}: ${wallet.mnemonic}`
-        await wallet.lock('password')
-        walletElements.push(walletElement)
-      }
-      card.replaceChildren(...walletElements)
-    }
+               function addToStorage (key, value) {
+                       if (typeof value !== 'string') {
+                               throw new TypeError(`Cannot add ${typeof value} to storage`)
+                       }
+                       const item = JSON.parse(sessionStorage.getItem(key) ?? '[]')
+                       if (!Array.isArray(item)) {
+                               throw new TypeError(`Storage item is not an array`)
+                       }
+                       item.push(value)
+                       return new Promise((resolve, reject) => {
+                               try {
+                                       sessionStorage.setItem(key, JSON.stringify(item))
+                                       resolve()
+                               } catch (err) {
+                                       console.error(err)
+                                       reject(err)
+                               }
+                       })
+               }
+               function updateWalletForm () {
+                       const form = document.querySelector('#wallet-form')
+                       const walletTypeContainer = document.querySelector('#wallet-form-wallet-type')
+                       const walletType = walletTypeContainer.firstChild
+                       const importTypeContainer = document.querySelector('#wallet-form-import-type')
+                       const importType = importTypeContainer.firstChild
+                       const saltContainer = document.querySelector('#wallet-form-salt')
+                       if (walletType.value === 'bip44' && importType.value === 'mnemonic') {
+                               saltContainer.classList.remove('hide')
+                       } else {
+                               saltContainer.classList.add('hide')
+                       }
+                       document.querySelector('#wallet-form-import-value x-label').innerText = importType.value
+               }
+               async function showWallets () {
+                       const card = document.querySelector('#walletCard')
+                       const storedWalletData = JSON.parse(sessionStorage.getItem('wallets') ?? '[]')
+                       const wallets = []
+                       for (const walletData of storedWalletData) {
+                               const w = JSON.parse(walletData)
+                               console.dir(w)
+                               if (w.id && w.name && w.type) {
+                                       const walletType = getWalletType(w.type)
+                                       wallets.push(await walletType.restore(w.id))
+                               }
+                       }
+                       const walletElements = []
+                       for (const wallet of wallets) {
+                               const walletElement = document.createElement('x-label')
+                               await wallet.unlock('password')
+                               walletElement.innerText = `${wallet.name}: ${wallet.mnemonic}`
+                               await wallet.lock('password')
+                               walletElements.push(walletElement)
+                       }
+                       card.replaceChildren(...walletElements)
+               }
 
-    async function deriveAccounts () {
-      const wallet = document.querySelector('#wallet').value
-      const form = btn.querySelector('#account-form')
-      await console.log('deriveAccounts')
-    }
-    async function clearStorage () {
-      sessionStorage.clear()
-      notify.info(`Session storage cleared`)
-    }
-    const notify = {
-      _show: (msg, color) => {
-        const container = document.getElementById('notifications')
-        const notification = document.createElement('x-card')
+               async function deriveAccounts () {
+                       const wallet = document.querySelector('#wallet').value
+                       const form = btn.querySelector('#account-form')
+                       await console.log('deriveAccounts')
+               }
+               async function clearStorage () {
+                       sessionStorage.clear()
+                       notify.info(`Session storage cleared`)
+               }
+               const notify = {
+                       _show: (msg, color) => {
+                               const container = document.querySelector('#notifications')
+                               const notification = document.createElement('x-card')
 
-        notification.innerText = msg
-        notification.style.color = color ?? notification.style.color
+                               notification.innerText = msg
+                               notification.style.color = color ?? notification.style.color
 
-        notification.addEventListener('click', notification.remove)
-        container.appendChild(notification)
-      },
-      info: (msg) => notify._show(`ℹ️ ${msg}`),
-      ok: (msg) => notify._show(`☑️ ${msg}`, 'Cyan'),
-      warn: (msg) => notify._show(`⚠️ ${msg}`, 'Gold'),
-      error: (msg) => notify._show(`🚫 ${msg}`, 'Tomato')
-    }
-  </script>
-  <meta name="xel-theme" content="https://unpkg.com/xel@latest/themes/adwaita-dark.css" />
-  <meta name="xel-accent-color" content="blue" />
-  <meta name="xel-icons" content="https://unpkg.com/bootstrap-icons@latest/bootstrap-icons.svg" />
-  <style>
+                               notification.addEventListener('click', notification.remove)
+                               container.appendChild(notification)
+                       },
+                       info: (msg) => notify._show(`ℹ️ ${msg}`),
+                       ok: (msg) => notify._show(`☑️ ${msg}`, 'Cyan'),
+                       warn: (msg) => notify._show(`⚠️ ${msg}`, 'Gold'),
+                       error: (msg) => notify._show(`🚫 ${msg}`, 'Tomato')
+               }
+       </script>
+       <meta name="xel-theme" content="https://unpkg.com/xel@latest/themes/adwaita-dark.css" />
+       <meta name="xel-accent-color" content="blue" />
+       <meta name="xel-icons" content="https://unpkg.com/bootstrap-icons@latest/bootstrap-icons.svg" />
+       <style>
     body {
       background-color: slategrey;
       color: #209CE9;
 
 <body onload="load()" onhashchange="switchPage(event)" style="visibility:hidden;">
        <x-box id="notifications"></x-box>
-  <header>
-    <x-box id="wallets">
-      <x-select id="wallet" style="width:100%;" onchange="updateWallet()">
-        <x-menu>
-          <x-menuitem value="_new">
-            <x-label>New</x-label>
-          </x-menuitem>
-          <x-menuitem value="_import">
-            <x-label>Import</x-label>
-          </x-menuitem>
-          <hr />
-          <x-menuitem value="_ledger">
-            <x-label>Ledger</x-label>
-          </x-menuitem>
-          <hr />
-        </x-menu>
-      </x-select>
-      <dialog id="wallet-form">
-        <x-box vertical>
-          <x-box id="wallet-form-name">
-            <x-label>Name</x-label>
-            <x-input type="text"></x-input>
-          </x-box>
-          <x-box id="wallet-form-wallet-type">
-            <x-radios required onchange="updateWalletForm()">
-              <x-radio value="bip44"><x-label>BIP-44</x-label></x-radio>
-              <x-radio value="blake2b"><x-label>BLAKE2b</x-label></x-radio>
-            </x-radios>
-          </x-box>
-          <x-box id="wallet-form-import-type" class="hide">
-            <x-select onchange="updateWalletForm()">
-              <x-menu>
-                <x-menuitem value="mnemonic"><x-label>Import mnemonic</x-label></x-menuitem>
-                <x-menuitem value="seed"><x-label>Import seed</x-label></x-menuitem>
-              </x-menu>
-            </x-select>
-          </x-box>
-          <x-box id="wallet-form-import-value" class="hide">
-            <x-label style="text-transform:capitalize"></x-label>
-            <x-input type="password"></x-input>
-          </x-box>
-          <x-box id="wallet-form-salt" class="hide">
-            <x-label>Salt</x-label>
-            <x-input type="password">Optional</x-input>
-          </x-box>
-          <x-box id="wallet-form-password">
-            <x-label>Lock</x-label>
-            <x-input type="password" required><x-label>Password</x-label></x-input>
-          </x-box>
-          <x-box>
-            <x-buttons>
-              <x-button onclick="document.getElementById('wallet-form').close()">
-                Cancel
-              </x-button>
-              <x-button onclick="createWallet().then(w => { console.log(w);showWallets() })">
-                OK
-              </x-button>
-            </x-buttons>
-          </x-box>
-        </x-box>
-      </dialog>
-    </x-box><!-- end #wallets-->
-    <x-box id="accounts">
-      <x-select id="account" style="width:100%;" onchange="updateAccount()">
-        <x-menu>
-          <x-menuitem value="_new">
-            <x-label>New</x-label>
-          </x-menuitem>
-          <x-menuitem value="_import">
-            <x-label>Import</x-label>
-          </x-menuitem>
-          <hr />
-        </x-menu>
-      </x-select>
-      <x-button>
-        <x-icon href="#cash-stack"></x-icon>
-        <x-label>New Account</x-label>
-        <dialog id="account-form">
-          <x-box vertical>
-            <x-box>
-              <x-label>Name</x-label>
-              <x-input type="text"></x-input>
-            </x-box>
-            <x-box>
-              <x-label>Index (optional)</x-label>
-              <x-numberinput min="0" max="2147483647"></x-numberinput>
-            </x-box>
-            <x-buttons>
-              <x-button onclick="document.getElementById('account-form').close()">
-                Cancel
-              </x-button>
-              <x-button onclick="deriveAccounts(this).then(w => { console.log(w);showWallets() })">
-                OK
-              </x-button>
-            </x-buttons>
-          </x-box>
-        </dialog>
-      </x-button>
-    </x-box><!-- end #accounts -->
-  </header>
-  <main>
-    <x-box id="exchange" class="page">
-      <h1>Exchange</h1>
-    </x-box><!-- end #exchange -->
-    <x-box id="history" class="page">
-      <h1>History</h1>
-    </x-box><!-- end #history -->
-    <x-box id="transact" class="page">
-      <h1>Transact</h1>
-      <x-card id="walletCard">
-      </x-card>
-    </x-box><!-- end #transact -->
-    <x-box id="rolodex" class="page">
-      <h1>Rolodex</h1>
-    </x-box><!-- end #rolodex -->
-    <x-box id="settings" class="page">
-      <h1>Settings</h1>
-      <x-button onclick="clearStorage()">
-        <x-label>Clear Storage</x-label>
-      </x-button>
-    </x-box><!-- end #settings -->
-  </main>
-  <nav>
-    <a href="#exchange">
-      <x-icon href="#currency-exchange"></x-icon>
-    </a>
-    <a href="#history">
-      <x-icon href="#book-half"></x-icon>
-    </a>
-    <a href="#transact" id="xno">
-      <svg width="0px" height="0px" viewBox="0 0 1080 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
-        <circle cx="540" cy="540" r="540" fill="currentcolor" />
-        <path
-          d="M792.911 881H740.396L541.099 570.561L338.761 881H286.68L513.452 529.3L306.882 206.222H360.42L541.95 490.393L727.322 206.222H777.555L568.762 528.379L792.911 881Z"
-          fill="white" />
-        <path
-          d="M336.487 508.737H744.807V547.116H336.487V508.737ZM336.487 623.872H744.824V662.251H336.47L336.487 623.872Z"
-          fill="white" />
-      </svg>
-    </a>
-    <a href="#rolodex">
-      <x-icon href="#person-rolodex"></x-icon>
-    </a>
-    <a href="#settings">
-      <x-icon href="#gear"></x-icon>
-    </a>
-  </nav>
+       <header>
+               <x-box id="wallets">
+                       <x-select id="wallet" style="width:100%;" onchange="updateWallet()">
+                               <x-menu>
+                                       <x-menuitem value="_new">
+                                               <x-label>New</x-label>
+                                       </x-menuitem>
+                                       <x-menuitem value="_import">
+                                               <x-label>Import</x-label>
+                                       </x-menuitem>
+                                       <hr />
+                                       <x-menuitem value="_ledger">
+                                               <x-label>Ledger</x-label>
+                                       </x-menuitem>
+                                       <hr />
+                               </x-menu>
+                       </x-select>
+                       <dialog id="wallet-form">
+                               <x-box vertical>
+                                       <x-box id="wallet-form-name">
+                                               <x-label>Name</x-label>
+                                               <x-input type="text"></x-input>
+                                       </x-box>
+                                       <x-box id="wallet-form-wallet-type">
+                                               <x-radios required onchange="updateWalletForm()">
+                                                       <x-radio value="bip44"><x-label>BIP-44</x-label></x-radio>
+                                                       <x-radio value="blake2b"><x-label>BLAKE2b</x-label></x-radio>
+                                               </x-radios>
+                                       </x-box>
+                                       <x-box id="wallet-form-import-type" class="hide">
+                                               <x-select onchange="updateWalletForm()">
+                                                       <x-menu>
+                                                               <x-menuitem value="mnemonic"><x-label>Import mnemonic</x-label></x-menuitem>
+                                                               <x-menuitem value="seed"><x-label>Import seed</x-label></x-menuitem>
+                                                       </x-menu>
+                                               </x-select>
+                                       </x-box>
+                                       <x-box id="wallet-form-import-value" class="hide">
+                                               <x-label style="text-transform:capitalize"></x-label>
+                                               <x-input type="password"></x-input>
+                                       </x-box>
+                                       <x-box id="wallet-form-salt" class="hide">
+                                               <x-label>Salt</x-label>
+                                               <x-input type="password">Optional</x-input>
+                                       </x-box>
+                                       <x-box id="wallet-form-password">
+                                               <x-label>Lock</x-label>
+                                               <x-input type="password" required><x-label>Password</x-label></x-input>
+                                       </x-box>
+                                       <x-box>
+                                               <x-buttons>
+                                                       <x-button onclick="document.querySelector('#wallet-form').close()">
+                                                               Cancel
+                                                       </x-button>
+                                                       <x-button onclick="createWallet().then(w => { console.log(w);showWallets() })">
+                                                               OK
+                                                       </x-button>
+                                               </x-buttons>
+                                       </x-box>
+                               </x-box>
+                       </dialog>
+               </x-box><!-- end #wallets-->
+               <x-box id="accounts">
+                       <x-select id="account" style="width:100%;" onchange="updateAccount()">
+                               <x-menu>
+                                       <x-menuitem value="_new">
+                                               <x-label>New</x-label>
+                                       </x-menuitem>
+                                       <x-menuitem value="_import">
+                                               <x-label>Import</x-label>
+                                       </x-menuitem>
+                                       <hr />
+                               </x-menu>
+                       </x-select>
+                       <x-button>
+                               <x-icon href="#cash-stack"></x-icon>
+                               <x-label>New Account</x-label>
+                               <dialog id="account-form">
+                                       <x-box vertical>
+                                               <x-box>
+                                                       <x-label>Name</x-label>
+                                                       <x-input type="text"></x-input>
+                                               </x-box>
+                                               <x-box>
+                                                       <x-label>Index (optional)</x-label>
+                                                       <x-numberinput min="0" max="2147483647"></x-numberinput>
+                                               </x-box>
+                                               <x-buttons>
+                                                       <x-button onclick="document.querySelector('#account-form').close()">
+                                                               Cancel
+                                                       </x-button>
+                                                       <x-button onclick="deriveAccounts(this).then(w => { console.log(w);showWallets() })">
+                                                               OK
+                                                       </x-button>
+                                               </x-buttons>
+                                       </x-box>
+                               </dialog>
+                       </x-button>
+               </x-box><!-- end #accounts -->
+       </header>
+       <main>
+               <x-box id="exchange" class="page">
+                       <h1>Exchange</h1>
+               </x-box><!-- end #exchange -->
+               <x-box id="history" class="page">
+                       <h1>History</h1>
+               </x-box><!-- end #history -->
+               <x-box id="transact" class="page">
+                       <h1>Transact</h1>
+                       <x-card id="walletCard">
+                       </x-card>
+               </x-box><!-- end #transact -->
+               <x-box id="rolodex" class="page">
+                       <h1>Rolodex</h1>
+               </x-box><!-- end #rolodex -->
+               <x-box id="settings" class="page">
+                       <h1>Settings</h1>
+                       <x-button onclick="clearStorage()">
+                               <x-label>Clear Storage</x-label>
+                       </x-button>
+               </x-box><!-- end #settings -->
+       </main>
+       <nav>
+               <a href="#exchange">
+                       <x-icon href="#currency-exchange"></x-icon>
+               </a>
+               <a href="#history">
+                       <x-icon href="#book-half"></x-icon>
+               </a>
+               <a href="#transact" id="xno">
+                       <svg width="0px" height="0px" viewBox="0 0 1080 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
+                               <circle cx="540" cy="540" r="540" fill="currentcolor" />
+                               <path
+                                       d="M792.911 881H740.396L541.099 570.561L338.761 881H286.68L513.452 529.3L306.882 206.222H360.42L541.95 490.393L727.322 206.222H777.555L568.762 528.379L792.911 881Z"
+                                       fill="white" />
+                               <path
+                                       d="M336.487 508.737H744.807V547.116H336.487V508.737ZM336.487 623.872H744.824V662.251H336.47L336.487 623.872Z"
+                                       fill="white" />
+                       </svg>
+               </a>
+               <a href="#rolodex">
+                       <x-icon href="#person-rolodex"></x-icon>
+               </a>
+               <a href="#settings">
+                       <x-icon href="#gear"></x-icon>
+               </a>
+       </nav>
 </body>