gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-backoffice] branch master updated (379e8f2 -> e1bc057)


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated (379e8f2 -> e1bc057)
Date: Mon, 08 Feb 2021 21:35:25 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a change to branch master
in repository merchant-backoffice.

    from 379e8f2  switch to axios, updated typescript and other minor changes
     new a03c489  added icons
     new 386d067  removing stories directory
     new a4eb77b  configuring storybook with styling
     new e14a2bf  missing babelrc for storybook
     new 54ef0ca  removed until needed
     new e1bc057  working on instances listing

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 {src => .storybook}/.babelrc                       |   0
 .storybook/main.js                                 |   1 +
 .storybook/preview.js                              |   1 +
 package.json                                       |   2 +
 src/components/auth/LoginPage.tsx                  |  15 +
 src/components/hooks/backend.ts                    |  47 +++
 src/components/navbar/index.tsx                    |  69 +---
 src/components/sidebar/index.tsx                   |  35 +-
 src/declaration.d.ts                               | 421 ++++++++++++++++++++-
 src/routes/index.tsx                               |  20 +-
 src/routes/instanceDetail/index.tsx                |   6 +
 src/routes/instances/{table.tsx => Table.tsx}      |  10 +-
 src/routes/instances/View.stories.tsx              |  35 ++
 src/routes/instances/View.tsx                      |  74 ++++
 src/routes/instances/index.tsx                     | 127 +------
 .../fonts/XRXV3I6Li01BKofINeaE.ttf                 | Bin
 src/{assets => scss}/fonts/nunito.css              |   2 +-
 .../fonts/materialdesignicons-webfont-4.9.95.eot   | Bin 0 -> 844600 bytes
 .../fonts/materialdesignicons-webfont-4.9.95.ttf   | Bin 0 -> 844380 bytes
 .../fonts/materialdesignicons-webfont-4.9.95.woff  | Bin 0 -> 404384 bytes
 .../fonts/materialdesignicons-webfont-4.9.95.woff2 | Bin 0 -> 283040 bytes
 src/scss/icons/materialdesignicons-4.9.95.min.css  |   3 +
 src/stories/Button.js                              |  51 ---
 src/stories/Button.stories.js                      |  37 --
 src/stories/Header.js                              |  53 ---
 src/stories/Header.stories.js                      |  23 --
 src/stories/Introduction.stories.mdx               | 207 ----------
 src/stories/Page.js                                |  72 ----
 src/stories/Page.stories.js                        |  22 --
 src/stories/assets/code-brackets.svg               |   1 -
 src/stories/assets/colors.svg                      |   1 -
 src/stories/assets/comments.svg                    |   1 -
 src/stories/assets/direction.svg                   |   1 -
 src/stories/assets/flow.svg                        |   1 -
 src/stories/assets/plugin.svg                      |   1 -
 src/stories/assets/repo.svg                        |   1 -
 src/stories/assets/stackalt.svg                    |   1 -
 src/stories/button.css                             |  30 --
 src/stories/header.css                             |  26 --
 src/stories/page.css                               |  69 ----
 src/style.scss                                     |   7 -
 src/template.html                                  |   5 +-
 yarn.lock                                          |  44 +--
 43 files changed, 647 insertions(+), 875 deletions(-)
 copy {src => .storybook}/.babelrc (100%)
 create mode 100644 src/components/auth/LoginPage.tsx
 create mode 100644 src/components/hooks/backend.ts
 create mode 100644 src/routes/instanceDetail/index.tsx
 rename src/routes/instances/{table.tsx => Table.tsx} (93%)
 create mode 100644 src/routes/instances/View.stories.tsx
 create mode 100644 src/routes/instances/View.tsx
 rename src/{assets => scss}/fonts/XRXV3I6Li01BKofINeaE.ttf (100%)
 rename src/{assets => scss}/fonts/nunito.css (53%)
 create mode 100644 src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.eot
 create mode 100644 src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.ttf
 create mode 100644 src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff
 create mode 100644 
src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff2
 create mode 100644 src/scss/icons/materialdesignicons-4.9.95.min.css
 delete mode 100644 src/stories/Button.js
 delete mode 100644 src/stories/Button.stories.js
 delete mode 100644 src/stories/Header.js
 delete mode 100644 src/stories/Header.stories.js
 delete mode 100644 src/stories/Introduction.stories.mdx
 delete mode 100644 src/stories/Page.js
 delete mode 100644 src/stories/Page.stories.js
 delete mode 100644 src/stories/assets/code-brackets.svg
 delete mode 100644 src/stories/assets/colors.svg
 delete mode 100644 src/stories/assets/comments.svg
 delete mode 100644 src/stories/assets/direction.svg
 delete mode 100644 src/stories/assets/flow.svg
 delete mode 100644 src/stories/assets/plugin.svg
 delete mode 100644 src/stories/assets/repo.svg
 delete mode 100644 src/stories/assets/stackalt.svg
 delete mode 100644 src/stories/button.css
 delete mode 100644 src/stories/header.css
 delete mode 100644 src/stories/page.css
 delete mode 100644 src/style.scss

diff --git a/src/.babelrc b/.storybook/.babelrc
similarity index 100%
copy from src/.babelrc
copy to .storybook/.babelrc
diff --git a/.storybook/main.js b/.storybook/main.js
index 26dfeaf..b9dea09 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -4,6 +4,7 @@ module.exports = {
     "../src/**/*.stories.@(js|jsx|ts|tsx)"
   ],
   "addons": [
+    "@storybook/preset-scss",
     "@storybook/addon-links",
     "@storybook/addon-essentials"
   ]
diff --git a/.storybook/preview.js b/.storybook/preview.js
index 5d00c02..15bd64e 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,3 +1,4 @@
+import "../src/scss/main.scss"
 
 export const parameters = {
   actions: { argTypesRegex: "^on[A-Z].*" },
diff --git a/package.json b/package.json
index 0c88c82..87f2b37 100644
--- a/package.json
+++ b/package.json
@@ -30,10 +30,12 @@
   },
   "devDependencies": {
     "@babel/core": "^7.12.13",
+    "@babel/plugin-transform-react-jsx-source": "^7.12.13",
     "@storybook/addon-actions": "^6.1.16",
     "@storybook/addon-essentials": "^6.1.16",
     "@storybook/addon-links": "^6.1.16",
     "@storybook/preact": "^6.1.16",
+    "@storybook/preset-scss": "^1.0.3",
     "@types/enzyme": "^3.10.5",
     "@types/jest": "^26.0.8",
     "@typescript-eslint/eslint-plugin": "^2.25.0",
diff --git a/src/components/auth/LoginPage.tsx 
b/src/components/auth/LoginPage.tsx
new file mode 100644
index 0000000..427de64
--- /dev/null
+++ b/src/components/auth/LoginPage.tsx
@@ -0,0 +1,15 @@
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+
+interface Props {
+  onLogIn: (token: string) => void;
+}
+
+export default function LoginPage({ onLogIn }: Props): VNode {
+  const [token, update] = useState('')
+
+  return <div>
+    <input value={token} onInput={e => update(e?.currentTarget.value)} />
+    <button onClick={(): void => onLogIn(token)}>set</button>
+  </div>
+}
\ No newline at end of file
diff --git a/src/components/hooks/backend.ts b/src/components/hooks/backend.ts
new file mode 100644
index 0000000..ba322f0
--- /dev/null
+++ b/src/components/hooks/backend.ts
@@ -0,0 +1,47 @@
+import useSWR, { mutate } from 'swr';
+import axios from 'axios'
+import { MerchantBackend } from '../../declaration';
+
+type HttpResponse<T> = HttpResponseOk<T> | HttpResponseError<T>;
+
+interface HttpResponseOk<T> {
+  data: T;
+}
+interface HttpResponseError<T> {
+  data: undefined;
+  needsAuth: boolean;
+  error: Error;
+}
+
+class AuthError extends Error {
+  public readonly isAuth = true
+}
+
+const BACKEND = 'http://localhost:9966'
+const TOKEN_KEY = 'backend-token'
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+async function fetcher(url: string): Promise<any> {
+  const token = localStorage.getItem(TOKEN_KEY)
+  const headers = token ? { Authorization: `Bearer secret-token:${token}` } : 
undefined
+
+  const res = await axios.get(`${BACKEND}/private/${url}`, { headers })
+  if (res.status == 200) return res.data
+  if (res.status == 401) throw new AuthError()
+
+  const error = new Error('An error occurred while fetching the data.')
+  const info = res.data
+  const status = res.status
+  throw { info, status, ...error }
+}
+
+export function updateToken(token: string): void {
+  localStorage.setItem(TOKEN_KEY, token)
+  mutate('instances')
+}
+
+export function useBackendInstances(): 
HttpResponse<MerchantBackend.Instances.InstancesResponse> {
+  const { data, error } = 
useSWR<MerchantBackend.Instances.InstancesResponse>('instances', fetcher)
+
+  return { data, needsAuth: error instanceof AuthError, error }
+}
diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx
index 18f30ce..86e981b 100644
--- a/src/components/navbar/index.tsx
+++ b/src/components/navbar/index.tsx
@@ -16,73 +16,8 @@ export default function NavigationBar(): VNode {
           <span class="icon"><i class="mdi mdi-dots-vertical" /></span>
         </a>
       </div>
-      <div class="navbar-menu fadeIn animated faster" id="navbar-menu">
-        <div class="navbar-end">
-          <div class="navbar-item has-dropdown has-dropdown-with-icons 
has-divider is-hoverable">
-            <a class="navbar-link is-arrowless">
-              <span class="icon"><i class="mdi mdi-menu" /></span>
-              <span>Sample Menu</span>
-              <span class="icon">
-                <i class="mdi mdi-chevron-down" />
-              </span>
-            </a>
-            <div class="navbar-dropdown">
-              <a href="/profile" class="navbar-item">
-                <span class="icon"><i class="mdi mdi-account" /></span>
-                <span>My Profile</span>
-              </a>
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-settings" /></span>
-                <span>Settings</span>
-              </a>
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-email" /></span>
-                <span>Messages</span>
-              </a>
-              <hr class="navbar-divider" />
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-logout" /></span>
-                <span>Log Out</span>
-              </a>
-            </div>
-          </div>
-          <div class="navbar-item has-dropdown has-dropdown-with-icons 
has-divider has-user-avatar is-hoverable">
-            <a class="navbar-link is-arrowless">
-              <div class="is-user-avatar">
-                <img 
src="https://avatars.dicebear.com/4.5/api/male/john-doe.svg"; alt="John Doe" />
-              </div>
-              <div class="is-user-name"><span>John Doe</span></div>
-              <span class="icon"><i class="mdi mdi-chevron-down" /></span>
-            </a>
-            <div class="navbar-dropdown">
-              <a href="/profile" class="navbar-item">
-                <span class="icon"><i class="mdi mdi-account" /></span>
-                <span>My Profile</span>
-              </a>
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-settings" /></span>
-                <span>Settings</span>
-              </a>
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-email" /></span>
-                <span>Messages</span>
-              </a>
-              <hr class="navbar-divider" />
-              <a class="navbar-item">
-                <span class="icon"><i class="mdi mdi-logout" /></span>
-                <span>Log Out</span>
-              </a>
-            </div>
-          </div>
-          <a href="https://taler.net"; title="About" class="navbar-item 
has-divider is-desktop-icon-only">
-            <span class="icon"><i class="mdi mdi-help-circle-outline" /></span>
-            <span>About</span>
-          </a>
-          <a title="Log out" class="navbar-item is-desktop-icon-only">
-            <span class="icon"><i class="mdi mdi-logout" /></span>
-            <span>Log out</span>
-          </a>
-        </div>
+      <div class="navbar-menu navbar-end">
+        <button class="button is-primary">Log out</button>
       </div>
     </nav>
   );
diff --git a/src/components/sidebar/index.tsx b/src/components/sidebar/index.tsx
index f686eb0..fe569aa 100644
--- a/src/components/sidebar/index.tsx
+++ b/src/components/sidebar/index.tsx
@@ -5,59 +5,44 @@ export default function Sidebar(): VNode {
     <aside class="aside is-placed-left is-expanded">
       <div class="aside-tools">
         <div class="aside-tools-label">
-          <span><b>Admin</b> One HTML</span>
+          <span><b>Taler</b> Merchant Backend</span>
         </div>
       </div>
       <div class="menu is-menu-main">
         <p class="menu-label">General</p>
         <ul class="menu-list">
           <li>
-            <a href="/" class="is-active router-link-active has-icon">
+            <a href="/instances" class="is-active router-link-active has-icon">
               <span class="icon"><i class="mdi mdi-desktop-mac" /></span>
-              <span class="menu-item-label">Dashboard</span>
+              <span class="menu-item-label">Instances</span>
             </a>
           </li>
         </ul>
-        <p class="menu-label">Examples</p>
+        <p class="menu-label">Instance</p>
         <ul class="menu-list">
           <li>
             <a href="/instances" class="has-icon">
               <span class="icon has-update-mark"><i class="mdi mdi-table" 
/></span>
-              <span class="menu-item-label">Instances</span>
+              <span class="menu-item-label">Manage</span>
             </a>
           </li>
           <li>
             <a href="/forms" class="has-icon">
               <span class="icon"><i class="mdi mdi-square-edit-outline" 
/></span>
-              <span class="menu-item-label">Forms</span>
+              <span class="menu-item-label">Orders</span>
             </a>
           </li>
           <li>
             <a href="/profile" class="has-icon">
               <span class="icon"><i class="mdi mdi-account-circle" /></span>
-              <span class="menu-item-label">Profile</span>
+              <span class="menu-item-label">Inventory</span>
             </a>
           </li>
           <li>
-            <a class="has-icon has-dropdown-icon">
-              <span class="icon"><i class="mdi mdi-view-list" /></span>
-              <span class="menu-item-label">Submenus</span>
-              <div class="dropdown-icon">
-                <span class="icon"><i class="mdi mdi-plus" /></span>
-              </div>
+            <a href="/profile" class="has-icon">
+              <span class="icon"><i class="mdi mdi-account-circle" /></span>
+              <span class="menu-item-label">Tipping</span>
             </a>
-            <ul>
-              <li>
-                <a href="#void">
-                  <span>Sub-item One</span>
-                </a>
-              </li>
-              <li>
-                <a href="#void">
-                  <span>Sub-item Two</span>
-                </a>
-              </li>
-            </ul>
           </li>
         </ul>
         <p class="menu-label">About</p>
diff --git a/src/declaration.d.ts b/src/declaration.d.ts
index 4b14502..bd31d17 100644
--- a/src/declaration.d.ts
+++ b/src/declaration.d.ts
@@ -1,4 +1,3 @@
-import StringRenderer from 
"enzyme-adapter-preact-pure/build/src/StringRenderer";
 
 declare module "*.css" {
     const mapping: Record<string, string>;
@@ -9,14 +8,416 @@ declare module "*.scss" {
     export default mapping;
 }
 
-namespace MerchantBackend {
-    type PrivateInstances = {
-        instances: Instance[];
-    };
-    type Instance = {
+type EddsaPublicKey = string;
+// type RelativeTime = Duration;
+interface Timestamp {
+    // Milliseconds since epoch, or the special
+    // value "forever" to represent an event that will
+    // never happen.
+    t_ms: number | "never";
+}
+interface Duration {
+    // Duration in milliseconds or "forever"
+    // to represent an infinite duration.
+    d_ms: number | "forever";
+}
+
+type Amount = string;
+type UUID = string;
+type Integer = number;
+
+export namespace MerchantBackend {
+    // Delivery location, loosely modeled as a subset of
+    // ISO20022's PostalAddress25.
+    interface Tax {
+        // the name of the tax
         name: string;
-        id: string;
-        merchant_pub: string;
-        payment_targets: string[];
+
+        // amount paid in tax
+        tax: Amount;
+    }
+
+    interface Location {
+        // Nation with its own government.
+        country?: string;
+
+        // Identifies a subdivision of a country such as state, region, county.
+        country_subdivision?: string;
+
+        // Identifies a subdivision within a country sub-division.
+        district?: string;
+
+        // Name of a built-up area, with defined boundaries, and a local 
government.
+        town?: string;
+
+        // Specific location name within the town.
+        town_location?: string;
+
+        // Identifier consisting of a group of letters and/or numbers that
+        // is added to a postal address to assist the sorting of mail.
+        post_code?: string;
+
+        // Name of a street or thoroughfare.
+        street?: string;
+
+        // Name of the building or house.
+        building_name?: string;
+
+        // Number that identifies the position of a building on a street.
+        building_number?: string;
+
+        // Free-form address lines, should not exceed 7 elements.
+        address_lines?: string[];
+    }
+    namespace Instances {
+
+        //POST /private/instances
+        interface InstanceConfigurationMessage {
+            // The URI where the wallet will send coins.  A merchant may have
+            // multiple accounts, thus this is an array.  Note that by
+            // removing URIs from this list the respective account is set to
+            // inactive and thus unavailable for new contracts, but preserved
+            // in the database as existing offers and contracts may still refer
+            // to it.
+            payto_uris: string[];
+
+            // Name of the merchant instance to create (will become $INSTANCE).
+            id: string;
+
+            // Merchant name corresponding to this instance.
+            name: string;
+
+            // "Authentication" header required to authorize management access 
the instance.
+            // Optional, if not given authentication will be disabled for
+            // this instance (hopefully authentication checks are still
+            // done by some reverse proxy).
+            auth_token?: string;
+
+            // The merchant's physical address (to be put into contracts).
+            address: Location;
+
+            // The jurisdiction under which the merchant conducts its business
+            // (to be put into contracts).
+            jurisdiction: Location;
+
+            // Maximum wire fee this instance is willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_wire_fee: Amount;
+
+            // Default factor for wire fee amortization calculations.
+            // Can be overridden by the frontend on a per-order basis.
+            default_wire_fee_amortization: Integer;
+
+            // Maximum deposit fee (sum over all coins) this instance is 
willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_deposit_fee: Amount;
+
+            //  If the frontend does NOT specify an execution date, how long 
should
+            // we tell the exchange to wait to aggregate transactions before
+            // executing the wire transfer?  This delay is added to the current
+            // time when we generate the advisory execution time for the 
exchange.
+            default_wire_transfer_delay: RelativeTime;
+
+            // If the frontend does NOT specify a payment deadline, how long 
should
+            // offers we make be valid by default?
+            default_pay_delay: RelativeTime;
+
+        }
+
+        // PATCH /private/instances/$INSTANCE
+        interface InstanceReconfigurationMessage {
+            // The URI where the wallet will send coins.  A merchant may have
+            // multiple accounts, thus this is an array.  Note that by
+            // removing URIs from this list
+            payto_uris: string[];
+
+            // Merchant name corresponding to this instance.
+            name: string;
+
+            // "Authentication" header required to authorize management access 
the instance.
+            // Optional, if not given authentication will be disabled for
+            // this instance (hopefully authentication checks are still
+            // done by some reverse proxy).
+            auth_token?: string;
+
+            // The merchant's physical address (to be put into contracts).
+            address: Location;
+
+            // The jurisdiction under which the merchant conducts its business
+            // (to be put into contracts).
+            jurisdiction: Location;
+
+            // Maximum wire fee this instance is willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_wire_fee: Amount;
+
+            // Default factor for wire fee amortization calculations.
+            // Can be overridden by the frontend on a per-order basis.
+            default_wire_fee_amortization: Integer;
+
+            // Maximum deposit fee (sum over all coins) this instance is 
willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_deposit_fee: Amount;
+
+            //  If the frontend does NOT specify an execution date, how long 
should
+            // we tell the exchange to wait to aggregate transactions before
+            // executing the wire transfer?  This delay is added to the current
+            // time when we generate the advisory execution time for the 
exchange.
+            default_wire_transfer_delay: RelativeTime;
+
+            // If the frontend does NOT specify a payment deadline, how long 
should
+            // offers we make be valid by default?
+            default_pay_delay: RelativeTime;
+
+        }
+
+        //   GET /private/instances
+        interface InstancesResponse {
+            // List of instances that are present in the backend (see Instance)
+            instances: Instance[];
+        }
+
+        interface Instance {
+            // Merchant name corresponding to this instance.
+            name: string;
+
+            // Merchant instance this response is about ($INSTANCE)
+            id: string;
+
+            // Public key of the merchant/instance, in Crockford Base32 
encoding.
+            merchant_pub: EddsaPublicKey;
+
+            // List of the payment targets supported by this instance. Clients 
can
+            // specify the desired payment target in /order requests.  Note 
that
+            // front-ends do not have to support wallets selecting payment 
targets.
+            payment_targets: string[];
+
+        }
+
+        //GET /private/instances/$INSTANCE
+        interface QueryInstancesResponse {
+            // The URI where the wallet will send coins.  A merchant may have
+            // multiple accounts, thus this is an array.
+            accounts: MerchantAccount[];
+
+            // Merchant name corresponding to this instance.
+            name: string;
+
+            // Public key of the merchant/instance, in Crockford Base32 
encoding.
+            merchant_pub: EddsaPublicKey;
+
+            // The merchant's physical address (to be put into contracts).
+            address: Location;
+
+            // The jurisdiction under which the merchant conducts its business
+            // (to be put into contracts).
+            jurisdiction: Location;
+
+            // Maximum wire fee this instance is willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_wire_fee: Amount;
+
+            // Default factor for wire fee amortization calculations.
+            // Can be overridden by the frontend on a per-order basis.
+            default_wire_fee_amortization: Integer;
+
+            // Maximum deposit fee (sum over all coins) this instance is 
willing to pay.
+            // Can be overridden by the frontend on a per-order basis.
+            default_max_deposit_fee: Amount;
+
+            //  If the frontend does NOT specify an execution date, how long 
should
+            // we tell the exchange to wait to aggregate transactions before
+            // executing the wire transfer?  This delay is added to the current
+            // time when we generate the advisory execution time for the 
exchange.
+            default_wire_transfer_delay: RelativeTime;
+
+            // If the frontend does NOT specify a payment deadline, how long 
should
+            // offers we make be valid by default?
+            default_pay_deadline: RelativeTime;
+
+        }
+
+        interface MerchantAccount {
+
+            // payto:// URI of the account.
+            payto_uri: string;
+
+            // Hash over the wire details (including over the salt)
+            h_wire: HashCode;
+
+            // salt used to compute h_wire
+            salt: HashCode;
+
+            // true if this account is active,
+            // false if it is historic.
+            active: boolean;
+        }
+
+        //   DELETE /private/instances/$INSTANCE
+
+
+    }
+
+    namespace Inventory {
+        // POST /private/products
+        interface ProductAddDetail {
+
+            // product ID to use.
+            product_id: string;
+
+            // Human-readable product description.
+            description: string;
+
+            // Map from IETF BCP 47 language tags to localized descriptions
+            // eslint-disable-next-line @typescript-eslint/camelcase
+            description_i18n: { [lang_tag: string]: string };
+
+            // unit in which the product is measured (liters, kilograms, 
packages, etc.)
+            unit: string;
+
+            // The price for one unit of the product. Zero is used
+            // to imply that this product is not sold separately, or
+            // that the price is not fixed, and must be supplied by the
+            // front-end.  If non-zero, this price MUST include applicable
+            // taxes.
+            price: Amount;
+
+            // An optional base64-encoded product image
+            image: ImageDataUrl;
+
+            // a list of taxes paid by the merchant for one unit of this 
product
+            taxes: Tax[];
+
+            // Number of units of the product in stock in sum in total,
+            // including all existing sales ever. Given in product-specific
+            // units.
+            // A value of -1 indicates "infinite" (i.e. for "electronic" 
books).
+            total_stock: Integer;
+
+            // Identifies where the product is in stock.
+            address: Location;
+
+            // Identifies when we expect the next restocking to happen.
+            next_restock?: Timestamp;
+
+        }
+        //   PATCH /private/products/$PRODUCT_ID
+        interface ProductPatchDetail {
+
+            // Human-readable product description.
+            description: string;
+
+            // Map from IETF BCP 47 language tags to localized descriptions
+            // eslint-disable-next-line @typescript-eslint/camelcase
+            description_i18n: { [lang_tag: string]: string };
+
+            // unit in which the product is measured (liters, kilograms, 
packages, etc.)
+            unit: string;
+
+            // The price for one unit of the product. Zero is used
+            // to imply that this product is not sold separately, or
+            // that the price is not fixed, and must be supplied by the
+            // front-end.  If non-zero, this price MUST include applicable
+            // taxes.
+            price: Amount;
+
+            // An optional base64-encoded product image
+            image: ImageDataUrl;
+
+            // a list of taxes paid by the merchant for one unit of this 
product
+            taxes: Tax[];
+
+            // Number of units of the product in stock in sum in total,
+            // including all existing sales ever. Given in product-specific
+            // units.
+            // A value of -1 indicates "infinite" (i.e. for "electronic" 
books).
+            total_stock: Integer;
+
+            // Number of units of the product that were lost (spoiled, stolen, 
etc.)
+            total_lost: Integer;
+
+            // Identifies where the product is in stock.
+            address: Location;
+
+            // Identifies when we expect the next restocking to happen.
+            next_restock?: Timestamp;
+
+        }
+
+        // GET /private/products
+        interface InventorySummaryResponse {
+            // List of products that are present in the inventory
+            products: InventoryEntry[];
+        }
+        interface InventoryEntry {
+            // Product identifier, as found in the product.
+            product_id: string;
+
+        }
+
+        // GET /private/products/$PRODUCT_ID
+        interface ProductDetail {
+
+            // Human-readable product description.
+            description: string;
+
+            // Map from IETF BCP 47 language tags to localized descriptions
+            // eslint-disable-next-line @typescript-eslint/camelcase
+            description_i18n: { [lang_tag: string]: string };
+
+            // unit in which the product is measured (liters, kilograms, 
packages, etc.)
+            unit: string;
+
+            // The price for one unit of the product. Zero is used
+            // to imply that this product is not sold separately, or
+            // that the price is not fixed, and must be supplied by the
+            // front-end.  If non-zero, this price MUST include applicable
+            // taxes.
+            price: Amount;
+
+            // An optional base64-encoded product image
+            image: ImageDataUrl;
+
+            // a list of taxes paid by the merchant for one unit of this 
product
+            taxes: Tax[];
+
+            // Number of units of the product in stock in sum in total,
+            // including all existing sales ever. Given in product-specific
+            // units.
+            // A value of -1 indicates "infinite" (i.e. for "electronic" 
books).
+            total_stock: Integer;
+
+            // Number of units of the product that have already been sold.
+            total_sold: Integer;
+
+            // Number of units of the product that were lost (spoiled, stolen, 
etc.)
+            total_lost: Integer;
+
+            // Identifies where the product is in stock.
+            address: Location;
+
+            // Identifies when we expect the next restocking to happen.
+            next_restock?: Timestamp;
+
+        }
+
+        // POST /private/products/$PRODUCT_ID/lock
+        interface LockRequest {
+
+            // UUID that identifies the frontend performing the lock
+            // It is suggested that clients use a timeflake for this,
+            // see https://github.com/anthonynsimon/timeflake
+            lock_uuid: UUID;
+
+            // How long does the frontend intend to hold the lock
+            duration: RelativeTime;
+
+            // How many units should be locked?
+            quantity: Integer;
+
+        }
+
+        //   DELETE /private/products/$PRODUCT_ID
+
     }
-}
\ No newline at end of file
+}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index f3ce566..1543a1a 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -1,14 +1,20 @@
 import { h, VNode } from 'preact';
-import { Route, Router } from 'preact-router';
+import { route, Route, Router } from 'preact-router';
 
 import NotFoundPage from './notfound';
 import Instances from './instances';
-import Dash from './dashboard';
-import BulmaForms from './forms';
-import BulmaProfile from './profile';
 import Footer from '../components/footer';
 import Sidebar from '../components/sidebar';
 import NavigationBar from '../components/navbar';
+import { useEffect } from 'preact/hooks';
+import InstanceDetail from './instanceDetail';
+
+function Redirector({ to }: { path: string; to: string }): null {
+  useEffect(() => {
+    route(to, true);
+  })
+  return null;
+}
 
 export default function PageRouter(): VNode {
   return (
@@ -16,10 +22,8 @@ export default function PageRouter(): VNode {
       <NavigationBar />
       <Sidebar />
       <Router>
-        <Route path="/dashboard" component={Dash} />
-        <Route path="/instances" component={Instances} />
-        <Route path="/forms" component={BulmaForms} />
-        <Route path="/profile" component={BulmaProfile} />
+        <Route path="/" component={Instances} />
+        <Route path="/i/:instance" component={InstanceDetail} />
         <NotFoundPage default />
       </Router>
       <Footer />
diff --git a/src/routes/instanceDetail/index.tsx 
b/src/routes/instanceDetail/index.tsx
new file mode 100644
index 0000000..e80a65a
--- /dev/null
+++ b/src/routes/instanceDetail/index.tsx
@@ -0,0 +1,6 @@
+import { h, VNode } from 'preact';
+
+
+export default function InstanceDetail({ instance }: any): VNode {
+  return <div>hola {instance}</div>
+}
\ No newline at end of file
diff --git a/src/routes/instances/table.tsx b/src/routes/instances/Table.tsx
similarity index 93%
rename from src/routes/instances/table.tsx
rename to src/routes/instances/Table.tsx
index f9b16e3..c3a0572 100644
--- a/src/routes/instances/table.tsx
+++ b/src/routes/instances/Table.tsx
@@ -2,10 +2,10 @@ import { h, VNode } from "preact";
 import { MerchantBackend } from "../../declaration";
 
 interface Props {
-  instances: MerchantBackend.Instance[];
+  instances: MerchantBackend.Instances.Instance[];
 }
 
-export default function Table({instances}:Props): VNode {
+export default function Table({ instances }: Props): VNode {
   return <div class="b-table has-pagination">
     <div class="table-wrapper has-mobile-cards">
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -18,8 +18,8 @@ export default function Table({instances}:Props): VNode {
               </label>
             </th>
             <th />
-            <th>Name</th>
-            <th>Company</th>
+            <th>id</th>
+            <th>name</th>
             <th>City</th>
             <th>Progress</th>
             <th>Created</th>
@@ -27,7 +27,7 @@ export default function Table({instances}:Props): VNode {
           </tr>
         </thead>
         <tbody>
-          { instances.map( i => {
+          {instances.map(i => {
             return <tr>
               <td class="is-checkbox-cell">
                 <label class="b-checkbox checkbox">
diff --git a/src/routes/instances/View.stories.tsx 
b/src/routes/instances/View.stories.tsx
new file mode 100644
index 0000000..a508298
--- /dev/null
+++ b/src/routes/instances/View.stories.tsx
@@ -0,0 +1,35 @@
+/* eslint-disable @typescript-eslint/camelcase */
+import { h } from 'preact';
+import View from './View'
+
+
+export default {
+  title: 'Instances/View',
+  component: View,
+  argTypes: {
+    onLogin: { action: 'onLogin' },
+    onLogout: { action: 'onLogout' },
+    onCreateAccount: { action: 'onCreateAccount' },
+  },
+};
+
+export const Empty = () => <View instances={[]} />
+
+export const WithDefaultInstance = () => <View instances={[{
+  id: 'default',
+  name: 'the default instance',
+  merchant_pub: 'abcdef',
+  payment_targets: []
+}]} />
+
+export const WithTwoInstance = () => <View instances={[{
+  id: 'first',
+  name: 'the first instance',
+  merchant_pub: 'abcdefgh',
+  payment_targets: []
+},{
+  id: 'second',
+  name: 'other instance',
+  merchant_pub: 'zxcvvbnm',
+  payment_targets: ['pay-to']
+}]} />
diff --git a/src/routes/instances/View.tsx b/src/routes/instances/View.tsx
new file mode 100644
index 0000000..b209726
--- /dev/null
+++ b/src/routes/instances/View.tsx
@@ -0,0 +1,74 @@
+import { h, VNode } from "preact";
+import { MerchantBackend } from "../../declaration";
+import Table from './Table';
+
+interface Props {
+  instances: MerchantBackend.Instances.Instance[];
+}
+
+export default function View({ instances }: Props): VNode {
+  return <div id="app">
+    <section class="section is-title-bar">
+      <div class="level">
+        <div class="level-left">
+          <div class="level-item">
+            <ul>
+              <li>Merchant</li>
+              <li>Instances</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </section>
+    <section class="hero is-hero-bar">
+      <div class="hero-body">
+        <div class="level">
+          <div class="level-left">
+            <div class="level-item">
+              <h1 class="title">List of configured instances</h1>
+            </div>
+          </div>
+          <div class="level-right" style="display: none;">
+            <div class="level-item" />
+          </div>
+        </div>
+      </div>
+    </section>
+    <section class="section is-main-section">
+      <div class="card has-table">
+        <header class="card-header">
+          <p class="card-header-title">
+            <span class="icon"><i class="mdi mdi-account-multiple" /></span>
+          Instances
+        </p>
+          <a href="#" class="card-header-icon">
+            <span class="icon"><i class="mdi mdi-reload" /></span>
+          </a>
+        </header>
+        <div class="card-content">
+          <Table instances={instances} />
+        </div>
+      </div>
+
+    </section>
+
+    <div id="sample-modal" class="modal">
+      <div class="modal-background jb-modal-close" />
+      <div class="modal-card">
+        <header class="modal-card-head">
+          <p class="modal-card-title">Confirm action</p>
+          <button class="delete jb-modal-close" aria-label="close" />
+        </header>
+        <section class="modal-card-body">
+          <p>This will permanently delete <b>Some Object</b></p>
+          <p>This is sample modal</p>
+        </section>
+        <footer class="modal-card-foot">
+          <button class="button jb-modal-close">Cancel</button>
+          <button class="button is-danger jb-modal-close">Delete</button>
+        </footer>
+      </div>
+      <button class="modal-close is-large jb-modal-close" aria-label="close" />
+    </div>
+  </div>
+}
\ No newline at end of file
diff --git a/src/routes/instances/index.tsx b/src/routes/instances/index.tsx
index aa0a8f0..0aeef3e 100644
--- a/src/routes/instances/index.tsx
+++ b/src/routes/instances/index.tsx
@@ -1,130 +1,15 @@
 import { h, VNode } from 'preact';
-import { useState } from 'preact/hooks';
-import useSWR, { mutate } from 'swr';
-import Table from './table';
-import { MerchantBackend } from '../../declaration';
-import axios from 'axios'
+import View from './View';
+import LoginPage from '../../components/auth/LoginPage';
+import { updateToken, useBackendInstances } from 
'../../components/hooks/backend';
 
-class AuthError extends Error {
-  public readonly isAuth = true
-}
 
-const BACKEND = 'http://localhost:9966'
-
-async function fetcher(url: string) {
-  const token = localStorage.getItem('backend-token')
-  const headers = token ? { Authorization: `Bearer secret-token:${token}` } : 
undefined
-
-  const res = await axios.get(`${BACKEND}/private/${url}`, {headers})
-  if (res.status == 200) return res.data
-  if (res.status == 401) throw new AuthError()
-
-  const error = new Error('An error occurred while fetching the data.')
-  const info = res.data
-  const status = res.status
-  throw { info, status, ...error }
-}
-
-function updateToken(token: string): void {
-  localStorage.setItem('backend-token', token)
-  mutate('instances')
-}
-
-type HttpResponse<T> = HttpResponseOk<T> | HttpResponseError<T>;
-
-interface HttpResponseOk<T> {
-  data: T;
-}
-interface HttpResponseError<T> {
-  data: undefined;
-  needsAuth: boolean;
-  error: Error;
-}
-
-
-function useBackendInstances(): HttpResponse<MerchantBackend.PrivateInstances> 
{
-  const { data, error } = 
useSWR<MerchantBackend.PrivateInstances>('instances', fetcher)
-  return { data, needsAuth: error instanceof AuthError, error }
-}
-
-function TokenModal(): VNode {
-  const [token, update] = useState('')
-
-  return <div>
-    <input value={token} onInput={e => update(e?.currentTarget.value)} />
-    <button onClick={(): void => updateToken(token)}>set</button>
-  </div>
-}
-
-export default function BulmaTable({}): VNode {
+export default function Instances(): VNode {
   const resp = useBackendInstances()
 
   if (!resp.data) {
-    return <TokenModal />
+    return <LoginPage onLogIn={updateToken} />
   }
 
-  return <div id="app">
-    <section class="section is-title-bar">
-      <div class="level">
-        <div class="level-left">
-          <div class="level-item">
-            <ul>
-              <li>Admin2</li>
-              <li>Tables</li>
-            </ul>
-          </div>
-        </div>
-      </div>
-    </section>
-    <section class="hero is-hero-bar">
-      <div class="hero-body">
-        <div class="level">
-          <div class="level-left">
-            <div class="level-item"><h1 class="title">
-              Responsive Tables
-          </h1></div>
-          </div>
-          <div class="level-right" style="display: none;">
-            <div class="level-item" />
-          </div>
-        </div>
-      </div>
-    </section>
-    <section class="section is-main-section">
-      <div class="card has-table">
-        <header class="card-header">
-          <p class="card-header-title">
-            <span class="icon"><i class="mdi mdi-account-multiple" /></span>
-          Instances
-        </p>
-          <a href="#" class="card-header-icon">
-            <span class="icon"><i class="mdi mdi-reload" /></span>
-          </a>
-        </header>
-        <div class="card-content">
-          <Table instances={resp.data.instances} />
-        </div>
-      </div>
-
-    </section>
-
-    <div id="sample-modal" class="modal">
-      <div class="modal-background jb-modal-close" />
-      <div class="modal-card">
-        <header class="modal-card-head">
-          <p class="modal-card-title">Confirm action</p>
-          <button class="delete jb-modal-close" aria-label="close" />
-        </header>
-        <section class="modal-card-body">
-          <p>This will permanently delete <b>Some Object</b></p>
-          <p>This is sample modal</p>
-        </section>
-        <footer class="modal-card-foot">
-          <button class="button jb-modal-close">Cancel</button>
-          <button class="button is-danger jb-modal-close">Delete</button>
-        </footer>
-      </div>
-      <button class="modal-close is-large jb-modal-close" aria-label="close" />
-    </div>
-  </div>;
+  return <View instances={resp.data.instances} />;
 }
\ No newline at end of file
diff --git a/src/assets/fonts/XRXV3I6Li01BKofINeaE.ttf 
b/src/scss/fonts/XRXV3I6Li01BKofINeaE.ttf
similarity index 100%
rename from src/assets/fonts/XRXV3I6Li01BKofINeaE.ttf
rename to src/scss/fonts/XRXV3I6Li01BKofINeaE.ttf
diff --git a/src/assets/fonts/nunito.css b/src/scss/fonts/nunito.css
similarity index 53%
rename from src/assets/fonts/nunito.css
rename to src/scss/fonts/nunito.css
index 5a6fb2c..ba965de 100644
--- a/src/assets/fonts/nunito.css
+++ b/src/scss/fonts/nunito.css
@@ -2,5 +2,5 @@
   font-family: 'Nunito';
   font-style: normal;
   font-weight: 400;
-  src: url(/assets/fonts/XRXV3I6Li01BKofINeaE.ttf) format('truetype');
+  src: url(./XRXV3I6Li01BKofINeaE.ttf) format('truetype');
 }
diff --git a/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.eot 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.eot
new file mode 100644
index 0000000..ab6b25d
Binary files /dev/null and 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.eot differ
diff --git a/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.ttf 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.ttf
new file mode 100644
index 0000000..824be10
Binary files /dev/null and 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.ttf differ
diff --git a/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff
new file mode 100644
index 0000000..7e087c1
Binary files /dev/null and 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff differ
diff --git a/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff2 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff2
new file mode 100644
index 0000000..b5caa4d
Binary files /dev/null and 
b/src/scss/icons/fonts/materialdesignicons-webfont-4.9.95.woff2 differ
diff --git a/src/scss/icons/materialdesignicons-4.9.95.min.css 
b/src/scss/icons/materialdesignicons-4.9.95.min.css
new file mode 100644
index 0000000..24a89d6
--- /dev/null
+++ b/src/scss/icons/materialdesignicons-4.9.95.min.css
@@ -0,0 +1,3 @@
+@font-face{font-family:"Material Design 
Icons";src:url("./fonts/materialdesignicons-webfont-4.9.95.eot");src:url("./fonts/materialdesignicons-webfont-4.9.95.woff2")
 format("woff2"),url("./fonts/materialdesignicons-webfont-4.9.95.woff") 
format("woff"),url("./fonts/materialdesignicons-webfont-4.9.95.ttf") 
format("truetype");font-weight:normal;font-style:normal}.mdi:before,.mdi-set{display:inline-block;font:normal
 normal normal 24px/1 "Material Design Icons";font-size:inherit;text-rendering 
[...]
+
+/*# sourceMappingURL=materialdesignicons.css.map */
diff --git a/src/stories/Button.js b/src/stories/Button.js
deleted file mode 100644
index 83ee575..0000000
--- a/src/stories/Button.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/** @jsx h */
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-import './button.css';
-
-/**
- * Primary UI component for user interaction
- */
-export const Button = ({ primary, backgroundColor, size, label, ...props }) => 
{
-  const mode = primary ? 'storybook-button--primary' : 
'storybook-button--secondary';
-  return (
-    <button
-      type="button"
-      className={['storybook-button', `storybook-button--${size}`, 
mode].join(' ')}
-      style={backgroundColor && { backgroundColor }}
-      {...props}
-    >
-      {label}
-    </button>
-  );
-};
-
-Button.propTypes = {
-  /**
-   * Is this the principal call to action on the page?
-   */
-  primary: PropTypes.bool,
-  /**
-   * What background color to use
-   */
-  backgroundColor: PropTypes.string,
-  /**
-   * How large should the button be?
-   */
-  size: PropTypes.oneOf(['small', 'medium', 'large']),
-  /**
-   * Button contents
-   */
-  label: PropTypes.string.isRequired,
-  /**
-   * Optional click handler
-   */
-  onClick: PropTypes.func,
-};
-
-Button.defaultProps = {
-  backgroundColor: null,
-  primary: false,
-  size: 'medium',
-  onClick: undefined,
-};
diff --git a/src/stories/Button.stories.js b/src/stories/Button.stories.js
deleted file mode 100644
index 6e88f08..0000000
--- a/src/stories/Button.stories.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/** @jsx h */
-import { h } from 'preact';
-import { Button } from './Button';
-
-export default {
-  title: 'Example/Button',
-  component: Button,
-  argTypes: {
-    backgroundColor: { control: 'color' },
-    onClick: { action: 'onClick' },
-  },
-};
-
-const Template = (args) => <Button {...args} />;
-
-export const Primary = Template.bind({});
-Primary.args = {
-  primary: true,
-  label: 'Button',
-};
-
-export const Secondary = Template.bind({});
-Secondary.args = {
-  label: 'Button',
-};
-
-export const Large = Template.bind({});
-Large.args = {
-  size: 'large',
-  label: 'Button',
-};
-
-export const Small = Template.bind({});
-Small.args = {
-  size: 'small',
-  label: 'Button',
-};
diff --git a/src/stories/Header.js b/src/stories/Header.js
deleted file mode 100644
index f425ec1..0000000
--- a/src/stories/Header.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/** @jsx h */
-import { h, Fragment } from 'preact';
-import PropTypes from 'prop-types';
-
-import { Button } from './Button';
-import './header.css';
-
-export const Header = ({ user, onLogin, onLogout, onCreateAccount }) => (
-  <header>
-    <div className="wrapper">
-      <div>
-        <svg width="32" height="32" viewBox="0 0 32 32" 
xmlns="http://www.w3.org/2000/svg";>
-          <g fill="none" fillRule="evenodd">
-            <path
-              d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 
22V10A10 10 0 0110 0z"
-              fill="#FFF"
-            />
-            <path
-              d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 
5.6V4.4z"
-              fill="#555AB9"
-            />
-            <path
-              d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 
10l9.7-5.5z"
-              fill="#91BAF8"
-            />
-          </g>
-        </svg>
-        <h1>Acme</h1>
-      </div>
-      <div>
-        {user ? (
-          <Button size="small" onClick={onLogout} label="Log out" />
-        ) : (
-          <Fragment>
-            <Button size="small" onClick={onLogin} label="Log in" />
-            <Button primary size="small" onClick={onCreateAccount} label="Sign 
up" />
-          </Fragment>
-        )}
-      </div>
-    </div>
-  </header>
-);
-
-Header.propTypes = {
-  user: PropTypes.shape({}),
-  onLogin: PropTypes.func.isRequired,
-  onLogout: PropTypes.func.isRequired,
-  onCreateAccount: PropTypes.func.isRequired,
-};
-
-Header.defaultProps = {
-  user: null,
-};
diff --git a/src/stories/Header.stories.js b/src/stories/Header.stories.js
deleted file mode 100644
index 6b580f9..0000000
--- a/src/stories/Header.stories.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/** @jsx h */
-import { h } from 'preact';
-import { Header } from './Header';
-
-export default {
-  title: 'Example/Header',
-  component: Header,
-  argTypes: {
-    onLogin: { action: 'onLogin' },
-    onLogout: { action: 'onLogout' },
-    onCreateAccount: { action: 'onCreateAccount' },
-  },
-};
-
-const Template = (args) => <Header {...args} />;
-
-export const LoggedIn = Template.bind({});
-LoggedIn.args = {
-  user: {},
-};
-
-export const LoggedOut = Template.bind({});
-LoggedOut.args = {};
diff --git a/src/stories/Introduction.stories.mdx 
b/src/stories/Introduction.stories.mdx
deleted file mode 100644
index d974095..0000000
--- a/src/stories/Introduction.stories.mdx
+++ /dev/null
@@ -1,207 +0,0 @@
-import { Meta } from '@storybook/addon-docs/blocks';
-import Code from './assets/code-brackets.svg';
-import Colors from './assets/colors.svg';
-import Comments from './assets/comments.svg';
-import Direction from './assets/direction.svg';
-import Flow from './assets/flow.svg';
-import Plugin from './assets/plugin.svg';
-import Repo from './assets/repo.svg';
-import StackAlt from './assets/stackalt.svg';
-
-<Meta title="Example/Introduction" />
-
-<style>{`
-  .subheading {
-    --mediumdark: '#999999';
-    font-weight: 900;
-    font-size: 13px;
-    color: #999;
-    letter-spacing: 6px;
-    line-height: 24px;
-    text-transform: uppercase;
-    margin-bottom: 12px;
-    margin-top: 40px;
-  }
-
-  .link-list {
-    display: grid;
-    grid-template-columns: 1fr;
-    grid-template-rows: 1fr 1fr;
-    row-gap: 10px;
-  }
-
-  @media (min-width: 620px) {
-    .link-list {
-      row-gap: 20px;
-      column-gap: 20px;
-      grid-template-columns: 1fr 1fr;
-    }
-  }
-
-  @media all and (-ms-high-contrast:none) {
-  .link-list {
-      display: -ms-grid;
-      -ms-grid-columns: 1fr 1fr;
-      -ms-grid-rows: 1fr 1fr;
-    }
-  }
-
-  .link-item {
-    display: block;
-    padding: 20px 30px 20px 15px;
-    border: 1px solid #00000010;
-    border-radius: 5px;
-    transition: background 150ms ease-out, border 150ms ease-out, transform 
150ms ease-out;
-    color: #333333;
-    display: flex;
-    align-items: flex-start;
-  }
-
-  .link-item:hover {
-    border-color: #1EA7FD50;
-    transform: translate3d(0, -3px, 0);
-    box-shadow: rgba(0, 0, 0, 0.08) 0 3px 10px 0;
-  }
-
-  .link-item:active {
-    border-color: #1EA7FD;
-    transform: translate3d(0, 0, 0);
-  }
-
-  .link-item strong {
-    font-weight: 700;
-    display: block;
-    margin-bottom: 2px;
-  }
-  
-  .link-item img {
-    height: 40px;
-    width: 40px;
-    margin-right: 15px;
-    flex: none;
-  }
-
-  .link-item span {
-    font-size: 14px;
-    line-height: 20px;
-  }
-
-  .tip {
-    display: inline-block;
-    border-radius: 1em;
-    font-size: 11px;
-    line-height: 12px;
-    font-weight: 700;
-    background: #E7FDD8;
-    color: #66BF3C;
-    padding: 4px 12px;
-    margin-right: 10px;
-    vertical-align: top;
-  }
-
-  .tip-wrapper {
-    font-size: 13px;
-    line-height: 20px;
-    margin-top: 40px;
-    margin-bottom: 40px;
-  }
-
-  .tip-wrapper code {
-    font-size: 12px;
-    display: inline-block;
-  }
-
-  
-`}</style>
-
-# Welcome to Storybook
-
-Storybook helps you build UI components in isolation from your app's business 
logic, data, and context.
-That makes it easy to develop hard-to-reach states. Save these UI states as 
**stories** to revisit during development, testing, or QA.
-
-Browse example stories now by navigating to them in the sidebar.
-View their code in the `src/stories` directory to learn how they work.
-We recommend building UIs with a 
[**component-driven**](https://componentdriven.org) process starting with 
atomic components and ending with pages.
-
-<div className="subheading">Configure</div>
-
-<div className="link-list">
-  <a className="link-item" 
href="https://storybook.js.org/docs/react/addons/addon-types"; target="_blank">
-    <img src={Plugin} alt="plugin" />
-    <span>
-      <strong>Presets for popular tools</strong>
-      Easy setup for TypeScript, SCSS and more.
-    </span>
-  </a>
-  <a
-    className="link-item"
-    href="https://storybook.js.org/docs/react/configure/webpack";
-    target="_blank"
-  >
-    <img src={StackAlt} alt="Build" />
-    <span>
-      <strong>Build configuration</strong>
-      How to customize webpack and Babel
-    </span>
-  </a>
-  <a
-    className="link-item"
-    href="https://storybook.js.org/docs/react/configure/styling-and-css";
-    target="_blank"
-  >
-    <img src={Colors} alt="colors" />
-    <span>
-      <strong>Styling</strong>
-      How to load and configure CSS libraries
-    </span>
-  </a>
-  <a
-    className="link-item"
-    
href="https://storybook.js.org/docs/react/get-started/setup#configure-storybook-for-your-stack";
-    target="_blank"
-  >
-    <img src={Flow} alt="flow" />
-    <span>
-      <strong>Data</strong>
-      Providers and mocking for data libraries
-    </span>
-  </a>
-</div>
-
-<div className="subheading">Learn</div>
-
-<div className="link-list">
-  <a className="link-item" href="https://storybook.js.org/docs"; 
target="_blank">
-    <img src={Repo} alt="repo" />
-    <span>
-      <strong>Storybook documentation</strong>
-      Configure, customize, and extend
-    </span>
-  </a>
-  <a className="link-item" href="https://www.learnstorybook.com"; 
target="_blank">
-    <img src={Direction} alt="direction" />
-    <span>
-      <strong>In-depth guides</strong>
-      Best practices from leading teams
-    </span>
-  </a>
-  <a className="link-item" href="https://github.com/storybookjs/storybook"; 
target="_blank">
-    <img src={Code} alt="code" />
-    <span>
-      <strong>GitHub project</strong>
-      View the source and add issues
-    </span>
-  </a>
-  <a className="link-item" href="https://discord.gg/UUt2PJb"; target="_blank">
-    <img src={Comments} alt="comments" />
-    <span>
-      <strong>Discord chat</strong>
-      Chat with maintainers and the community
-    </span>
-  </a>
-</div>
-
-<div className="tip-wrapper">
-  <span className="tip">Tip</span>Edit the Markdown in{' '}
-  <code>src/stories/Introduction.stories.mdx</code>
-</div>
diff --git a/src/stories/Page.js b/src/stories/Page.js
deleted file mode 100644
index e460596..0000000
--- a/src/stories/Page.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/** @jsx h */
-import { h } from 'preact';
-import PropTypes from 'prop-types';
-
-import { Header } from './Header';
-import './page.css';
-
-export const Page = ({ user, onLogin, onLogout, onCreateAccount }) => (
-  <article>
-    <Header user={user} onLogin={onLogin} onLogout={onLogout} 
onCreateAccount={onCreateAccount} />
-
-    <section>
-      <h2>Pages in Storybook</h2>
-      <p>
-        We recommend building UIs with a{' '}
-        <a href="https://componentdriven.org"; target="_blank" rel="noopener 
noreferrer">
-          <strong>component-driven</strong>
-        </a>{' '}
-        process starting with atomic components and ending with pages.
-      </p>
-      <p>
-        Render pages with mock data. This makes it easy to build and review 
page states without
-        needing to navigate to them in your app. Here are some handy patterns 
for managing page data
-        in Storybook:
-      </p>
-      <ul>
-        <li>
-          Use a higher-level connected component. Storybook helps you compose 
such data from the
-          "args" of child component stories
-        </li>
-        <li>
-          Assemble data in the page component from your services. You can mock 
these services out
-          using Storybook.
-        </li>
-      </ul>
-      <p>
-        Get a guided tutorial on component-driven development at{' '}
-        <a href="https://www.learnstorybook.com"; target="_blank" rel="noopener 
noreferrer">
-          Learn Storybook
-        </a>
-        . Read more in the{' '}
-        <a href="https://storybook.js.org/docs"; target="_blank" rel="noopener 
noreferrer">
-          docs
-        </a>
-        .
-      </p>
-      <div className="tip-wrapper">
-        <span className="tip">Tip</span> Adjust the width of the canvas with 
the{' '}
-        <svg width="10" height="10" viewBox="0 0 12 12" 
xmlns="http://www.w3.org/2000/svg";>
-          <g fill="none" fillRule="evenodd">
-            <path
-              d="M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 
01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 
0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 
5.2H2V10h3.8V6.2z"
-              id="a"
-              fill="#999"
-            />
-          </g>
-        </svg>
-        Viewports addon in the toolbar
-      </div>
-    </section>
-  </article>
-);
-Page.propTypes = {
-  user: PropTypes.shape({}),
-  onLogin: PropTypes.func.isRequired,
-  onLogout: PropTypes.func.isRequired,
-  onCreateAccount: PropTypes.func.isRequired,
-};
-
-Page.defaultProps = {
-  user: null,
-};
diff --git a/src/stories/Page.stories.js b/src/stories/Page.stories.js
deleted file mode 100644
index c01b13d..0000000
--- a/src/stories/Page.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/** @jsx h */
-import { h } from 'preact';
-
-import { Page } from './Page';
-import * as HeaderStories from './Header.stories';
-
-export default {
-  title: 'Example/Page',
-  component: Page,
-};
-
-const Template = (args) => <Page {...args} />;
-
-export const LoggedIn = Template.bind({});
-LoggedIn.args = {
-  ...HeaderStories.LoggedIn.args,
-};
-
-export const LoggedOut = Template.bind({});
-LoggedOut.args = {
-  ...HeaderStories.LoggedOut.args,
-};
diff --git a/src/stories/assets/code-brackets.svg 
b/src/stories/assets/code-brackets.svg
deleted file mode 100644
index 73de947..0000000
--- a/src/stories/assets/code-brackets.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/code-brackets</title><g 
id="illustration/code-brackets" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><path id="Combined-Shape" fill="#87E6E5" d="M11.4139325,12 
C11.7605938,12 12,12.5059743 12,13.3779712 L12,17.4951758 
L6.43502246,23.3839989 C5.85499251,23.9978337 5.85499251,25.0021663 
6.43502246,25.6160011 L12,31 [...]
\ No newline at end of file
diff --git a/src/stories/assets/colors.svg b/src/stories/assets/colors.svg
deleted file mode 100644
index 17d58d5..0000000
--- a/src/stories/assets/colors.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/colors</title><g 
id="illustration/colors" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><circle id="Oval" cx="23.763" cy="16.192" r="13.271" 
fill="#FC521F" opacity=".6"/><circle id="Oval-Copy" cx="15.468" cy="32.308" 
r="13.271" fill="#66BF3C" opacity=".6"/><path id="Combined-Shape" 
fill="#FF5F95" d="M15.4683651,19 [...]
\ No newline at end of file
diff --git a/src/stories/assets/comments.svg b/src/stories/assets/comments.svg
deleted file mode 100644
index 6493a13..0000000
--- a/src/stories/assets/comments.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/comments</title><g 
id="illustration/comments" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><path id="Path" fill="#96D07C" d="M2.52730803,17.9196415 
C2.44329744,17.9745167 2.36370847,18.000488 2.29303375,18.000488 
C2.1197031,18.000488 2,17.8443588 2,17.5752855 L2,4 C2,1.790861 
3.790861,3.23296945e-13 6,3.23296945e [...]
\ No newline at end of file
diff --git a/src/stories/assets/direction.svg b/src/stories/assets/direction.svg
deleted file mode 100644
index 65676ac..0000000
--- a/src/stories/assets/direction.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/direction</title><g 
id="illustration/direction" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><path id="Combined-Shape" fill="#FFD476" 
d="M23.4917015,33.6030641 L2.93840258,31.4321033 C2.38917316,31.3740904 
1.99096346,30.8818233 2.04897631,30.3325939 C2.0747515,30.0885705 
2.18934861,29.8625419 2.37095722,29.697526 [...]
\ No newline at end of file
diff --git a/src/stories/assets/flow.svg b/src/stories/assets/flow.svg
deleted file mode 100644
index 8ac27db..0000000
--- a/src/stories/assets/flow.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/flow</title><g id="illustration/flow" 
fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><path 
id="Combined-Shape" fill="#79C9FC" fill-rule="nonzero" d="M30,29 C32.7614237,29 
35,26.7614237 35,24 C35,14.6111593 27.3888407,7 18,7 C8.61115925,7 1,14.6111593 
1,24 C1,33.3888407 8.61115925,41 18,41 C19.3333404,41 20.6447683, [...]
\ No newline at end of file
diff --git a/src/stories/assets/plugin.svg b/src/stories/assets/plugin.svg
deleted file mode 100644
index 29e5c69..0000000
--- a/src/stories/assets/plugin.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/plugin</title><g 
id="illustration/plugin" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><path id="Combined-Shape" fill="#79C9FC" d="M26,15.3994248 
C26,15.4091303 26,15.4188459 26,15.4285714 L26,21.4694881 
C25.8463595,21.4969567 25.6941676,21.51275 25.5873784,21.51275 
C25.4974117,21.51275 25.4230979,21.4768034 25.3 [...]
\ No newline at end of file
diff --git a/src/stories/assets/repo.svg b/src/stories/assets/repo.svg
deleted file mode 100644
index f386ee9..0000000
--- a/src/stories/assets/repo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/repo</title><g id="illustration/repo" 
fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><path 
id="Rectangle-62-Copy" fill="#B7F0EF" d="M27.2217723,9.04506931 
L41.2217723,6.2682098 C43.3886973,5.83840648 45.4937616,7.2466219 
45.9235649,9.41354696 C45.9743993,9.66983721 46,9.93049166 46,10.1917747 
L46,32.581381 C46,34.4 [...]
\ No newline at end of file
diff --git a/src/stories/assets/stackalt.svg b/src/stories/assets/stackalt.svg
deleted file mode 100644
index 9b7ad27..0000000
--- a/src/stories/assets/stackalt.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="48" height="48" version="1.1" 
viewBox="0 0 48 48"><title>illustration/stackalt</title><g 
id="illustration/stackalt" fill="none" fill-rule="evenodd" stroke="none" 
stroke-width="1"><path id="Combined-Shape" fill="#FFAE00" d="M23.8628277,0 
L23.8628277,48 L3.32291648,36.2491883 L3.32155653,11.9499781 L23.8628277,0 Z 
M23.8670509,0 L44.408322,11.9499781 L44.4069621,36.2491883 L23.8670509,48 
L23.8670509,0  [...]
\ No newline at end of file
diff --git a/src/stories/button.css b/src/stories/button.css
deleted file mode 100644
index dc91dc7..0000000
--- a/src/stories/button.css
+++ /dev/null
@@ -1,30 +0,0 @@
-.storybook-button {
-  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  font-weight: 700;
-  border: 0;
-  border-radius: 3em;
-  cursor: pointer;
-  display: inline-block;
-  line-height: 1;
-}
-.storybook-button--primary {
-  color: white;
-  background-color: #1ea7fd;
-}
-.storybook-button--secondary {
-  color: #333;
-  background-color: transparent;
-  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
-}
-.storybook-button--small {
-  font-size: 12px;
-  padding: 10px 16px;
-}
-.storybook-button--medium {
-  font-size: 14px;
-  padding: 11px 20px;
-}
-.storybook-button--large {
-  font-size: 16px;
-  padding: 12px 24px;
-}
diff --git a/src/stories/header.css b/src/stories/header.css
deleted file mode 100644
index acadc9e..0000000
--- a/src/stories/header.css
+++ /dev/null
@@ -1,26 +0,0 @@
-.wrapper {
-  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
-  padding: 15px 20px;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-}
-
-svg {
-  display: inline-block;
-  vertical-align: top;
-}
-
-h1 {
-  font-weight: 900;
-  font-size: 20px;
-  line-height: 1;
-  margin: 6px 0 6px 10px;
-  display: inline-block;
-  vertical-align: top;
-}
-
-button + button {
-  margin-left: 10px;
-}
diff --git a/src/stories/page.css b/src/stories/page.css
deleted file mode 100644
index 51c9d09..0000000
--- a/src/stories/page.css
+++ /dev/null
@@ -1,69 +0,0 @@
-section {
-  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  font-size: 14px;
-  line-height: 24px;
-  padding: 48px 20px;
-  margin: 0 auto;
-  max-width: 600px;
-  color: #333;
-}
-
-h2 {
-  font-weight: 900;
-  font-size: 32px;
-  line-height: 1;
-  margin: 0 0 4px;
-  display: inline-block;
-  vertical-align: top;
-}
-
-p {
-  margin: 1em 0;
-}
-
-a {
-  text-decoration: none;
-  color: #1ea7fd;
-}
-
-ul {
-  padding-left: 30px;
-  margin: 1em 0;
-}
-
-li {
-  margin-bottom: 8px;
-}
-
-.tip {
-  display: inline-block;
-  border-radius: 1em;
-  font-size: 11px;
-  line-height: 12px;
-  font-weight: 700;
-  background: #e7fdd8;
-  color: #66bf3c;
-  padding: 4px 12px;
-  margin-right: 10px;
-  vertical-align: top;
-}
-
-.tip-wrapper {
-  font-size: 13px;
-  line-height: 20px;
-  margin-top: 40px;
-  margin-bottom: 40px;
-}
-
-.tip-wrapper svg {
-  display: inline-block;
-  height: 12px;
-  width: 12px;
-  margin-right: 4px;
-  vertical-align: top;
-  margin-top: 3px;
-}
-
-.tip-wrapper svg path {
-  fill: #1ea7fd;
-}
diff --git a/src/style.scss b/src/style.scss
deleted file mode 100644
index 81fb1bc..0000000
--- a/src/style.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-@charset "utf-8";
-// Import *all* of Bulma - refer to the customization guide for more info on 
customizing Bulma:
-// https://bulma.io/documentation/customize/
-@import "~bulma/bulma";
-@import "~bulma/sass/utilities/initial-variables.sass";
-@import "~bulma/sass/utilities/_all.sass";
-@import "~bulma/sass/elements/_all.sass";
diff --git a/src/template.html b/src/template.html
index e17719a..49c1c88 100644
--- a/src/template.html
+++ b/src/template.html
@@ -6,9 +6,8 @@
                <meta name="viewport" 
content="width=device-width,initial-scale=1">
                <meta name="mobile-web-app-capable" content="yes">
                <meta name="apple-mobile-web-app-capable" content="yes">
-               <link rel="apple-touch-icon" 
href="/assets/icons/apple-touch-icon.png">
-               <link href="/assets/fonts/nunito.css" rel="stylesheet" 
type="text/css">
-                       <% preact.headEnd %>
+               <link rel="apple-touch-icon"           
href="/assets/icons/apple-touch-icon.png">
+               <% preact.headEnd %>
        </head>
        <body>
                <% preact.bodyEnd %>
diff --git a/yarn.lock b/yarn.lock
index 951ea97..8fdddeb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -746,6 +746,13 @@
   dependencies:
     "@babel/plugin-transform-react-jsx" "^7.12.12"
 
+"@babel/plugin-transform-react-jsx-source@^7.12.13":
+  version "7.12.13"
+  resolved 
"https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.13.tgz#051d76126bee5c9a6aa3ba37be2f6c1698856bcb";
+  integrity 
sha512-O5JJi6fyfih0WfDgIJXksSPhGP/G0fQpfxYy87sDc+1sFmsCS6wr3aAn+whbzkhbjtq4VMqLRaSzR6IsshIC0Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.12.13"
+
 "@babel/plugin-transform-react-jsx@^7.10.1", 
"@babel/plugin-transform-react-jsx@^7.12.1", 
"@babel/plugin-transform-react-jsx@^7.12.12", 
"@babel/plugin-transform-react-jsx@^7.12.13", 
"@babel/plugin-transform-react-jsx@^7.9.0":
   version "7.12.13"
   resolved 
"https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.13.tgz#6c9f993b9f6fb6f0e32a4821ed59349748576a3e";
@@ -1947,6 +1954,11 @@
     regenerator-runtime "^0.13.7"
     ts-dedent "^2.0.0"
 
+"@storybook/preset-scss@^1.0.3":
+  version "1.0.3"
+  resolved 
"https://registry.yarnpkg.com/@storybook/preset-scss/-/preset-scss-1.0.3.tgz#8ac834545c642dada0f64f510ef08dfb882e9737";
+  integrity 
sha512-o9Iz6wxPeNENrQa2mKlsDKynBfqU2uWaRP80HeWp4TkGgf7/x3DVF2O7yi9N0x/PI1qzzTTpxlQ90D62XmpiTw==
+
 "@storybook/router@6.1.17":
   version "6.1.17"
   resolved 
"https://registry.yarnpkg.com/@storybook/router/-/router-6.1.17.tgz#96746878c50c6c97c7de5a1b23a9503c5d648775";
@@ -4076,29 +4088,6 @@ chardet@^0.7.0:
   resolved 
"https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e";
   integrity 
sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
 
-chart.js@^2.9.3:
-  version "2.9.4"
-  resolved 
"https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684";
-  integrity 
sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==
-  dependencies:
-    chartjs-color "^2.1.0"
-    moment "^2.10.2"
-
-chartjs-color-string@^0.6.0:
-  version "0.6.0"
-  resolved 
"https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71";
-  integrity 
sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
-  dependencies:
-    color-name "^1.0.0"
-
-chartjs-color@^2.1.0:
-  version "2.4.1"
-  resolved 
"https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0";
-  integrity 
sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==
-  dependencies:
-    chartjs-color-string "^0.6.0"
-    color-convert "^1.9.3"
-
 check-types@^8.0.3:
   version "8.0.3"
   resolved 
"https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552";
@@ -4342,7 +4331,7 @@ collection-visit@^1.0.0:
     map-visit "^1.0.0"
     object-visit "^1.0.0"
 
-color-convert@^1.9.0, color-convert@^1.9.1, color-convert@^1.9.3:
+color-convert@^1.9.0, color-convert@^1.9.1:
   version "1.9.3"
   resolved 
"https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8";
   integrity 
sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -4621,7 +4610,7 @@ core-js@^2.4.0:
   resolved 
"https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec";
   integrity 
sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
 
-core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5, core-js@^3.8.3:
+core-js@^3.0.1, core-js@^3.0.4, core-js@^3.6.5:
   version "3.8.3"
   resolved 
"https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0";
   integrity 
sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==
@@ -9538,11 +9527,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
   resolved 
"https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e";
   integrity 
sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
-moment@^2.10.2:
-  version "2.29.1"
-  resolved 
"https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3";
-  integrity 
sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
-
 moo@^0.5.0:
   version "0.5.1"
   resolved 
"https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4";

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]