gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: mui text field, standard vari


From: gnunet
Subject: [taler-wallet-core] branch master updated: mui text field, standard variation
Date: Sat, 19 Mar 2022 04:25:50 +0100

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

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 65eb64cd mui text field, standard variation
65eb64cd is described below

commit 65eb64cd07dcaf1b57405189fcd054684d3f5e2f
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Mar 18 17:52:46 2022 -0300

    mui text field, standard variation
---
 packages/taler-wallet-webextension/package.json    |   6 +-
 .../src/mui/Button.stories.tsx                     | 133 ++++++++
 .../taler-wallet-webextension/src/mui/Button.tsx   |  87 +++++-
 .../src/mui/TextField.stories.tsx                  | 108 +++++++
 .../src/mui/TextField.tsx                          |  69 +++++
 .../src/mui/input/FormControl.tsx                  | 156 ++++++++++
 .../src/mui/input/FormHelperText.tsx               |  54 ++++
 .../src/mui/input/FormLabel.tsx                    |  67 ++++
 .../src/mui/input/InputBase.tsx                    | 258 ++++++++++++++++
 .../src/mui/input/InputFilled.tsx                  |   5 +
 .../src/mui/input/InputLabel.tsx                   |  98 ++++++
 .../src/mui/input/InputOutlined.tsx                |   5 +
 .../src/mui/input/InputStandard.tsx                | 124 ++++++++
 .../src/mui/input/SelectFilled.tsx                 |   5 +
 .../src/mui/input/SelectOutlined.tsx               |   5 +
 .../src/mui/input/SelectStandard.tsx               |   5 +
 .../taler-wallet-webextension/src/mui/style.tsx    |  16 +
 .../src/popupEntryPoint.tsx                        |   2 +-
 .../src/walletEntryPoint.tsx                       | 337 ++++++++++-----------
 .../static/img/delete_24px.svg                     |   1 +
 .../static/img/send_24px.svg                       |   1 +
 21 files changed, 1356 insertions(+), 186 deletions(-)

diff --git a/packages/taler-wallet-webextension/package.json 
b/packages/taler-wallet-webextension/package.json
index 03232dee..18563312 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -37,9 +37,6 @@
     "@babel/plugin-transform-react-jsx-source": "^7.12.13",
     "@babel/preset-typescript": "^7.13.0",
     "@gnu-taler/pogen": "workspace:*",
-    "@types/chai": "^4.3.0",
-    "chai": "^4.3.6",
-    "polished": "^4.1.4",
     "@linaria/babel-preset": "3.0.0-beta.4",
     "@linaria/core": "3.0.0-beta.4",
     "@linaria/react": "3.0.0-beta.4",
@@ -57,14 +54,17 @@
     "@storybook/preact": "6.4.18",
     "@testing-library/preact": "^2.0.1",
     "@testing-library/preact-hooks": "^1.1.0",
+    "@types/chai": "^4.3.0",
     "@types/chrome": "0.0.176",
     "@types/history": "^4.7.8",
     "@types/mocha": "^9.0.0",
     "@types/node": "^17.0.8",
     "babel-loader": "^8.2.3",
     "babel-plugin-transform-react-jsx": "^6.24.1",
+    "chai": "^4.3.6",
     "mocha": "^9.2.0",
     "nyc": "^15.1.0",
+    "polished": "^4.1.4",
     "preact-cli": "^3.3.5",
     "preact-render-to-string": "^5.1.19",
     "rimraf": "^3.0.2",
diff --git a/packages/taler-wallet-webextension/src/mui/Button.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/Button.stories.tsx
new file mode 100644
index 00000000..a6863add
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/Button.stories.tsx
@@ -0,0 +1,133 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { Button } from "./Button";
+import { Fragment, h } from "preact";
+import DeleteIcon from "../../static/img/delete_24px.svg";
+import SendIcon from "../../static/img/send_24px.svg";
+import { styled } from "@linaria/react";
+
+export default {
+  title: "mui/button",
+  component: Button,
+};
+
+const Stack = styled.div`
+  display: flex;
+  flex-direction: column;
+`;
+
+export const BasicExample = () => (
+  <Fragment>
+    <Stack>
+      <Button size="small" variant="text">
+        Text
+      </Button>
+      <Button size="small" variant="contained">
+        Contained
+      </Button>
+      <Button size="small" variant="outlined">
+        Outlined
+      </Button>
+    </Stack>
+    <Stack>
+      <Button variant="text">Text</Button>
+      <Button variant="contained">Contained</Button>
+      <Button variant="outlined">Outlined</Button>
+    </Stack>
+    <Stack>
+      <Button size="large" variant="text">
+        Text
+      </Button>
+      <Button size="large" variant="contained">
+        Contained
+      </Button>
+      <Button size="large" variant="outlined">
+        Outlined
+      </Button>
+    </Stack>
+  </Fragment>
+);
+
+export const Others = () => (
+  <Fragment>
+    <p>colors</p>
+    <Stack>
+      <Button color="secondary">Secondary</Button>
+      <Button variant="contained" color="success">
+        Success
+      </Button>
+      <Button variant="outlined" color="error">
+        Error
+      </Button>
+    </Stack>
+    <p>disabled</p>
+    <Stack>
+      <Button disabled variant="text">
+        Text
+      </Button>
+      <Button disabled variant="contained">
+        Contained
+      </Button>
+      <Button disabled variant="outlined">
+        Outlined
+      </Button>
+    </Stack>
+  </Fragment>
+);
+
+export const WithIcons = () => (
+  <Fragment>
+    <Stack>
+      <Button variant="outlined" size="small" startIcon={DeleteIcon}>
+        Delete
+      </Button>
+      <Button variant="contained" size="small" endIcon={SendIcon}>
+        Send
+      </Button>
+      <Button variant="text" size="small" endIcon={SendIcon}>
+        Send
+      </Button>
+    </Stack>
+    <Stack>
+      <Button variant="outlined" startIcon={DeleteIcon}>
+        Delete
+      </Button>
+      <Button variant="contained" endIcon={SendIcon}>
+        Send
+      </Button>
+      <Button variant="text" endIcon={SendIcon}>
+        Send
+      </Button>
+    </Stack>
+    <Stack>
+      <Button variant="outlined" size="large" startIcon={DeleteIcon}>
+        Delete
+      </Button>
+      <Button variant="contained" size="large" endIcon={SendIcon}>
+        Send
+      </Button>
+      <Button variant="text" size="large" endIcon={SendIcon}>
+        Send
+      </Button>
+    </Stack>
+  </Fragment>
+);
diff --git a/packages/taler-wallet-webextension/src/mui/Button.tsx 
b/packages/taler-wallet-webextension/src/mui/Button.tsx
index ccca360f..8da5b86b 100644
--- a/packages/taler-wallet-webextension/src/mui/Button.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Button.tsx
@@ -1,6 +1,6 @@
 import { ComponentChildren, h, VNode } from "preact";
 import { css } from "@linaria/core";
-import { theme, ripple } from "./style";
+import { theme, ripple, Colors } from "./style";
 import { alpha } from "./colors/manipulation";
 
 interface Props {
@@ -12,9 +12,9 @@ interface Props {
   fullWidth?: boolean;
   href?: string;
   size?: "small" | "medium" | "large";
-  startIcon?: VNode;
+  startIcon?: VNode | string;
   variant?: "contained" | "outlined" | "text";
-  color?: "primary" | "secondary" | "success" | "error" | "info" | "warning";
+  color?: Colors;
   onClick?: () => void;
 }
 
@@ -28,7 +28,7 @@ const baseStyle = css`
   outline: 0;
   border: 0;
   margin: 0;
-  border-radius: 0;
+  /* border-radius: 0; */
   padding: 0;
   cursor: pointer;
   user-select: none;
@@ -50,6 +50,17 @@ const button = css`
     color: ${theme.palette.action.disabled};
   }
 `;
+const colorIconVariant = {
+  outlined: css`
+    background-color: var(--color-main);
+  `,
+  contained: css`
+    background-color: var(--color-contrastText);
+  `,
+  text: css`
+    background-color: var(--color-main);
+  `,
+};
 
 const colorVariant = {
   outlined: css`
@@ -90,6 +101,47 @@ const colorVariant = {
   `,
 };
 
+const sizeIconVariant = {
+  outlined: {
+    small: css`
+      padding: 3px;
+      font-size: ${theme.pxToRem(7)};
+    `,
+    medium: css`
+      padding: 5px;
+    `,
+    large: css`
+      padding: 7px;
+      font-size: ${theme.pxToRem(10)};
+    `,
+  },
+  contained: {
+    small: css`
+      padding: 4px;
+      font-size: ${theme.pxToRem(13)};
+    `,
+    medium: css`
+      padding: 6px;
+    `,
+    large: css`
+      padding: 8px;
+      font-size: ${theme.pxToRem(10)};
+    `,
+  },
+  text: {
+    small: css`
+      padding: 4px;
+      font-size: ${theme.pxToRem(13)};
+    `,
+    medium: css`
+      padding: 6px;
+    `,
+    large: css`
+      padding: 8px;
+      font-size: ${theme.pxToRem(15)};
+    `,
+  },
+};
 const sizeVariant = {
   outlined: {
     small: css`
@@ -162,12 +214,18 @@ export function Button({
         css`
           margin-right: 8px;
           margin-left: -4px;
+          mask: var(--image) no-repeat center;
         `,
+        colorIconVariant[variant],
+        sizeIconVariant[variant][size],
         style,
       ].join(" ")}
-    >
-      {sip}
-    </span>
+      style={{
+        "--image": `url("${sip}")`,
+        "--color-main": theme.palette[color].main,
+        "--color-contrastText": theme.palette[color].contrastText,
+      }}
+    />
   );
   const endIcon = eip && (
     <span
@@ -175,12 +233,19 @@ export function Button({
         css`
           margin-right: -4px;
           margin-left: 8px;
+          mask: var(--image) no-repeat center;
         `,
+        colorIconVariant[variant],
+        sizeIconVariant[variant][size],
         style,
       ].join(" ")}
-    >
-      {eip}
-    </span>
+      style={{
+        "--image": `url("${eip}")`,
+        "--color-main": theme.palette[color].main,
+        "--color-contrastText": theme.palette[color].contrastText,
+        "--color-dark": theme.palette[color].dark,
+      }}
+    />
   );
   return (
     <button
@@ -196,8 +261,8 @@ export function Button({
       ].join(" ")}
       style={{
         "--color-main": theme.palette[color].main,
-        "--color-main-alpha-half": alpha(theme.palette[color].main, 0.5),
         "--color-contrastText": theme.palette[color].contrastText,
+        "--color-main-alpha-half": alpha(theme.palette[color].main, 0.5),
         "--color-dark": theme.palette[color].dark,
         "--color-main-alpha-opacity": alpha(
           theme.palette[color].main,
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
new file mode 100644
index 00000000..a2f7e1e6
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
@@ -0,0 +1,108 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { styled } from "@linaria/react";
+import { Fragment, h } from "preact";
+import { useState } from "preact/hooks";
+import { TextField, Props } from "./TextField";
+
+export default {
+  title: "mui/TextField",
+  component: TextField,
+};
+
+const Container = styled.div`
+  display: flex;
+  flex-direction: column;
+  & > * {
+    margin: 20px;
+  }
+`;
+
+const BasicExample = (variant: Props["variant"]) => {
+  const [value, onChange] = useState("");
+  return (
+    <Container>
+      <TextField variant={variant} label="Name" {...{ value, onChange }} />
+      <TextField
+        variant={variant}
+        type="password"
+        label="Password"
+        {...{ value, onChange }}
+      />
+      <TextField
+        disabled
+        variant={variant}
+        label="Country"
+        helperText="this is disabled"
+        value="disabled"
+      />
+      <TextField
+        error
+        variant={variant}
+        label="Something"
+        {...{ value, onChange }}
+      />
+      <TextField
+        error
+        disabled
+        variant={variant}
+        label="Disabled and Error"
+        value="disabled with error"
+        helperText="this field has an error"
+      />
+      <TextField
+        variant={variant}
+        required
+        label="Name"
+        {...{ value, onChange }}
+        helperText="this field is required"
+      />
+    </Container>
+  );
+};
+
+export const Standard = () => BasicExample("standard");
+export const Filled = () => BasicExample("filled");
+export const Outlined = () => BasicExample("outlined");
+
+export const Color = () => (
+  <Container>
+    <TextField
+      variant="standard"
+      label="Outlined secondary"
+      color="secondary"
+      focused
+    />
+    <TextField
+      label="Filled success"
+      variant="standard"
+      color="success"
+      focused
+    />
+    <TextField
+      label="Standard warning"
+      variant="standard"
+      color="warning"
+      focused
+    />
+  </Container>
+);
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.tsx 
b/packages/taler-wallet-webextension/src/mui/TextField.tsx
new file mode 100644
index 00000000..ada8d5d8
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/TextField.tsx
@@ -0,0 +1,69 @@
+import { ComponentChildren, h, VNode } from "preact";
+import { FormControl } from "./input/FormControl";
+import { FormHelperText } from "./input/FormHelperText";
+import { InputFilled } from "./input/InputFilled";
+import { InputLabel } from "./input/InputLabel";
+import { InputOutlined } from "./input/InputOutlined";
+import { InputStandard } from "./input/InputStandard";
+import { SelectFilled } from "./input/SelectFilled";
+import { SelectOutlined } from "./input/SelectOutlined";
+import { SelectStandard } from "./input/SelectStandard";
+import { Colors } from "./style";
+
+export interface Props {
+  autoComplete?: string;
+  autoFocus?: boolean;
+  color?: Colors;
+  disabled?: boolean;
+  error?: boolean;
+  fullWidth?: boolean;
+  helperText?: VNode | string;
+  id?: string;
+  label?: VNode | string;
+  margin?: "dense" | "normal" | "none";
+  maxRows?: number;
+  minRows?: number;
+  multiline?: boolean;
+  onChange?: (s: string) => void;
+  placeholder?: string;
+  required?: boolean;
+  focused?: boolean;
+  rows?: number;
+  select?: boolean;
+  type?: string;
+  value?: string;
+  variant?: "filled" | "outlined" | "standard";
+  children?: ComponentChildren;
+}
+
+export function TextField({
+  label,
+  select,
+  helperText,
+  children,
+  variant = "standard",
+  ...props
+}: Props): VNode {
+  // htmlFor={id} id={inputLabelId}
+  const Input = select ? selectVariant[variant] : inputVariant[variant];
+  // console.log("variant", Input);
+  return (
+    <FormControl {...props}>
+      {label && <InputLabel>{label}</InputLabel>}
+      <Input {...props}>{children}</Input>
+      {helperText && <FormHelperText>{helperText}</FormHelperText>}
+    </FormControl>
+  );
+}
+
+const inputVariant = {
+  standard: InputStandard,
+  filled: InputFilled,
+  outlined: InputOutlined,
+};
+
+const selectVariant = {
+  standard: SelectStandard,
+  filled: SelectFilled,
+  outlined: SelectOutlined,
+};
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
new file mode 100644
index 00000000..7a839570
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
@@ -0,0 +1,156 @@
+import { css } from "@linaria/core";
+import { ComponentChildren, createContext, h } from "preact";
+import { useContext, useState } from "preact/hooks";
+import { Colors } from "../style";
+
+export interface Props {
+  color: Colors;
+  disabled: boolean;
+  error: boolean;
+  focused: boolean;
+  fullWidth: boolean;
+  hiddenLabel: boolean;
+  required: boolean;
+  variant: "filled" | "outlined" | "standard";
+  margin: "none" | "normal" | "dense";
+  size: "medium" | "small";
+  children: ComponentChildren;
+}
+
+export const root = css`
+  display: inline-flex;
+  flex-direction: column;
+  position: relative;
+  min-width: 0px;
+  padding: 0px;
+  margin: 0px;
+  border: 0px;
+  vertical-align: top;
+`;
+
+const marginVariant = {
+  none: "",
+  normal: css`
+    margin-top: 16px;
+    margin-bottom: 8px;
+  `,
+  dense: css`
+    margin-top: 8px;
+    margin-bottom: 4px;
+  `,
+};
+const fullWidthStyle = css`
+  width: 100%;
+`;
+
+export function FormControl({
+  color = "primary",
+  disabled = false,
+  error = false,
+  focused: visuallyFocused,
+  fullWidth = false,
+  hiddenLabel = false,
+  margin = "none",
+  required = false,
+  size = "medium",
+  variant = "standard",
+  children,
+}: Partial<Props>) {
+  const [filled, setFilled] = useState(false);
+  const [focusedState, setFocused] = useState(false);
+  const focused =
+    visuallyFocused !== undefined && !disabled ? visuallyFocused : 
focusedState;
+
+  const value: FCCProps = {
+    color,
+    disabled,
+    error,
+    filled,
+    focused,
+    fullWidth,
+    hiddenLabel,
+    size,
+    onBlur: () => {
+      setFocused(false);
+    },
+    onEmpty: () => {
+      setFilled(false);
+    },
+    onFilled: () => {
+      setFilled(true);
+    },
+    onFocus: () => {
+      setFocused(true);
+    },
+    required,
+    variant,
+  };
+
+  return (
+    <div
+      class={[
+        root,
+        marginVariant[margin],
+        fullWidth ? fullWidthStyle : "",
+      ].join(" ")}
+    >
+      <FormControlContext.Provider value={value}>
+        {children}
+      </FormControlContext.Provider>
+    </div>
+  );
+}
+
+export interface FCCProps {
+  // adornedStart,
+  // setAdornedStart,
+  color: Colors;
+  disabled: boolean;
+  error: boolean;
+  filled: boolean;
+  focused: boolean;
+  fullWidth: boolean;
+  hiddenLabel: boolean;
+  size: "medium" | "small";
+  onBlur: () => void;
+  onEmpty: () => void;
+  onFilled: () => void;
+  onFocus: () => void;
+  // registerEffect,
+  required: boolean;
+  variant: "filled" | "outlined" | "standard";
+}
+
+export const FormControlContext = createContext<FCCProps | null>(null);
+
+const defaultContextValue: FCCProps = {
+  color: "primary",
+  disabled: false,
+  error: false,
+  filled: false,
+  focused: false,
+  fullWidth: false,
+  hiddenLabel: false,
+  size: "medium",
+  onBlur: () => {},
+  onEmpty: () => {},
+  onFilled: () => {},
+  onFocus: () => {},
+  required: false,
+  variant: "outlined",
+};
+
+function withoutUndefinedProperties(obj: any) {
+  return Object.keys(obj).reduce((acc, key) => {
+    const _acc: any = acc;
+    if (obj[key] !== undefined) _acc[key] = obj[key];
+    return _acc;
+  }, {});
+}
+
+export function useFormControl(props: Partial<FCCProps> = {}): FCCProps {
+  const ctx = useContext(FormControlContext);
+  const cleanedProps = withoutUndefinedProperties(props);
+  if (!ctx) return { ...defaultContextValue, ...cleanedProps };
+  return { ...ctx, ...cleanedProps };
+}
diff --git 
a/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
new file mode 100644
index 00000000..4854a638
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
@@ -0,0 +1,54 @@
+import { css } from "@linaria/core";
+import { ComponentChildren, h } from "preact";
+import { theme } from "../style";
+import { useFormControl } from "./FormControl";
+
+const root = css`
+  color: ${theme.palette.text.secondary};
+  text-align: left;
+  margin-top: 3px;
+  margin-bottom: 0px;
+  margin-right: 0px;
+  margin-left: 0px;
+`;
+const disabledStyle = css`
+  color: ${theme.palette.text.disabled};
+`;
+const errorStyle = css`
+  color: ${theme.palette.error.main};
+`;
+const sizeSmallStyle = css`
+  margin-top: 4px;
+`;
+const containedStyle = css`
+  margin-right: 14px;
+  margin-left: 14px;
+`;
+
+interface Props {
+  disabled?: boolean;
+  error?: boolean;
+  filled?: boolean;
+  focused?: boolean;
+  margin?: "dense";
+  required?: boolean;
+  children: ComponentChildren;
+}
+export function FormHelperText({ children, ...props }: Props) {
+  const fcs = useFormControl(props);
+  const contained = fcs.variant === "filled" || fcs.variant === "outlined";
+  return (
+    <p
+      class={[
+        root,
+        theme.typography.caption,
+        fcs.disabled && disabledStyle,
+        fcs.error && errorStyle,
+        fcs.size === "small" && sizeSmallStyle,
+        contained && containedStyle,
+      ].join(" ")}
+    >
+      {children}
+    </p>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
new file mode 100644
index 00000000..e5ca5326
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
@@ -0,0 +1,67 @@
+import { css } from "@linaria/core";
+import { ComponentChildren, h } from "preact";
+import { Colors, theme } from "../style";
+import { useFormControl } from "./FormControl";
+
+export interface Props {
+  class?: string;
+  disabled?: boolean;
+  error?: boolean;
+  filled?: boolean;
+  focused?: boolean;
+  required?: boolean;
+  color?: Colors;
+  children?: ComponentChildren;
+}
+
+const root = css`
+  color: ${theme.palette.text.secondary};
+  line-height: 1.4375em;
+  padding: 0px;
+  position: relative;
+  &[data-focused] {
+    color: var(--color-main);
+  }
+  &[data-disabled] {
+    color: ${theme.palette.text.disabled};
+  }
+  &[data-error] {
+    color: ${theme.palette.error.main};
+  }
+`;
+
+export function FormLabel({
+  disabled,
+  error,
+  filled,
+  focused,
+  required,
+  color,
+  class: _class,
+  children,
+  ...rest
+}: Props) {
+  const fcs = useFormControl({
+    disabled,
+    error,
+    filled,
+    focused,
+    required,
+    color,
+  });
+  return (
+    <label
+      data-focused={fcs.focused}
+      data-error={fcs.error}
+      data-disabled={fcs.disabled}
+      class={[_class, root, theme.typography.body1].join(" ")}
+      {...rest}
+      style={{
+        "--color-main": theme.palette[fcs.color].main,
+      }}
+    >
+      {children}
+      {fcs.required && <span data-error={fcs.error}>&thinsp;{"*"}</span>}
+    </label>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
new file mode 100644
index 00000000..5714eb1b
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
@@ -0,0 +1,258 @@
+import { css } from "@linaria/core";
+import { h, JSX } from "preact";
+import { useEffect, useLayoutEffect, useState } from "preact/hooks";
+import { theme } from "../style";
+import { FormControlContext, useFormControl } from "./FormControl";
+
+const rootStyle = css`
+  color: ${theme.palette.text.primary};
+  line-height: 1.4375em;
+  box-sizing: border-box;
+  position: relative;
+  cursor: text;
+  display: inline-flex;
+  align-items: center;
+`;
+const rootDisabledStyle = css`
+  color: ${theme.palette.text.disabled};
+  cursor: default;
+`;
+const rootMultilineStyle = css`
+  padding: 4px 0 5px;
+`;
+const fullWidthStyle = css`
+  width: "100%";
+`;
+
+export function InputBaseRoot({
+  class: _class,
+  disabled,
+  error,
+  multiline,
+  focused,
+  fullWidth,
+  children,
+}: any) {
+  const fcs = useFormControl({});
+  return (
+    <div
+      data-disabled={disabled}
+      data-focused={focused}
+      data-error={error}
+      class={[
+        _class,
+        rootStyle,
+        theme.typography.body1,
+        disabled && rootDisabledStyle,
+        multiline && rootMultilineStyle,
+        fullWidth && fullWidthStyle,
+      ].join(" ")}
+      style={{
+        "--color-main": theme.palette[fcs.color].main,
+      }}
+    >
+      {children}
+    </div>
+  );
+}
+
+const componentStyle = css`
+  font: inherit;
+  letter-spacing: inherit;
+  color: currentColor;
+  padding: 4px 0 5px;
+  border: 0px;
+  box-sizing: content-box;
+  background: none;
+  height: 1.4375em;
+  margin: 0px;
+  -webkit-tap-highlight-color: transparent;
+  display: block;
+  min-width: 0px;
+  width: 100%;
+  animation-name: "auto-fill-cancel";
+  animation-duration: 10ms;
+
+  @keyframes auto-fill {
+    from {
+      display: block;
+    }
+  }
+  @keyframes auto-fill-cancel {
+    from {
+      display: block;
+    }
+  }
+  &::placeholder {
+    color: "currentColor";
+    opacity: ${theme.palette.mode === "light" ? 0.42 : 0.5};
+    transition: ${theme.transitions.create("opacity", {
+      duration: theme.transitions.duration.shorter,
+    })};
+  }
+  &:focus {
+    outline: 0;
+  }
+  &:invalid {
+    box-shadow: none;
+  }
+  &::-webkit-search-decoration {
+    -webkit-appearance: none;
+  }
+  &:-webkit-autofill {
+    animation-duration: 5000s;
+    animation-name: auto-fill;
+  }
+`;
+const componentDisabledStyle = css`
+  opacity: 1;
+  --webkit-text-fill-color: ${theme.palette.text.disabled};
+`;
+const componentSmallStyle = css`
+  padding-top: 1px;
+`;
+const componentMultilineStyle = css`
+  height: auto;
+  resize: none;
+  padding: 0px;
+  padding-top: 0px;
+`;
+const searchStyle = css`
+  -moz-appearance: textfield;
+  -webkit-appearance: textfield;
+`;
+
+export function InputBaseComponent({
+  disabled,
+  size,
+  multiline,
+  type,
+  ...props
+}: any) {
+  return (
+    <input
+      disabled={disabled}
+      type={type}
+      class={[
+        componentStyle,
+        disabled && componentDisabledStyle,
+        size === "small" && componentSmallStyle,
+        multiline && componentMultilineStyle,
+        type === "search" && searchStyle,
+      ].join(" ")}
+      {...props}
+    />
+  );
+}
+
+export function InputBase({
+  Root = InputBaseRoot,
+  Input,
+  onChange,
+  name,
+  placeholder,
+  readOnly,
+  onKeyUp,
+  onKeyDown,
+  rows,
+  type = "text",
+  value,
+  onClick,
+  ...props
+}: any) {
+  const fcs = useFormControl(props);
+  // const [focused, setFocused] = useState(false);
+  useLayoutEffect(() => {
+    if (value && value !== "") {
+      fcs.onFilled();
+    } else {
+      fcs.onEmpty();
+    }
+  }, [value]);
+
+  const handleFocus = (event: JSX.TargetedFocusEvent<EventTarget>) => {
+    // Fix a bug with IE11 where the focus/blur events are triggered
+    // while the component is disabled.
+    if (fcs.disabled) {
+      event.stopPropagation();
+      return;
+    }
+
+    // if (onFocus) {
+    //   onFocus(event);
+    // }
+    // if (inputPropsProp.onFocus) {
+    //   inputPropsProp.onFocus(event);
+    // }
+
+    fcs.onFocus();
+  };
+
+  const handleBlur = () => {
+    // if (onBlur) {
+    //   onBlur(event);
+    // }
+    // if (inputPropsProp.onBlur) {
+    //   inputPropsProp.onBlur(event);
+    // }
+
+    fcs.onBlur();
+  };
+
+  const handleChange = (
+    event: JSX.TargetedEvent<HTMLElement & { value?: string }>,
+  ) => {
+    // if (inputPropsProp.onChange) {
+    //   inputPropsProp.onChange(event, ...args);
+    // }
+
+    // Perform in the willUpdate
+    if (onChange) {
+      onChange(event.currentTarget.value);
+    }
+  };
+
+  const handleClick = (
+    event: JSX.TargetedMouseEvent<HTMLElement & { value?: string }>,
+  ) => {
+    // if (inputRef.current && event.currentTarget === event.target) {
+    //   inputRef.current.focus();
+    // }
+
+    if (onClick) {
+      onClick(event.currentTarget.value);
+    }
+  };
+
+  if (!Input) {
+    Input = props.multiline ? TextareaAutoSize : InputBaseComponent;
+  }
+
+  return (
+    <Root {...fcs} onClick={handleClick}>
+      <FormControlContext.Provider value={null}>
+        <Input
+          aria-invalid={fcs.error}
+          // aria-describedby={}
+          disabled={fcs.disabled}
+          name={name}
+          placeholder={placeholder}
+          readOnly={readOnly}
+          required={fcs.required}
+          rows={rows}
+          value={value}
+          onKeyDown={onKeyDown}
+          onKeyUp={onKeyUp}
+          type={type}
+          onChange={handleChange}
+          onBlur={handleBlur}
+          onFocus={handleFocus}
+        />
+      </FormControlContext.Provider>
+    </Root>
+  );
+}
+
+export function TextareaAutoSize() {
+  return <input onClick={(e) => null} />;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
new file mode 100644
index 00000000..5c50a8b7
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function InputFilled(): VNode {
+  return <div />;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
new file mode 100644
index 00000000..c70c5bfc
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
@@ -0,0 +1,98 @@
+import { css } from "@linaria/core";
+import { ComponentChildren, h } from "preact";
+import { Colors, theme } from "../style";
+import { useFormControl } from "./FormControl";
+import { FormLabel } from "./FormLabel";
+
+const root = css`
+  display: block;
+  transform-origin: top left;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 100%;
+
+  &[data-form-control] {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    transform: translate(0, 20px) scale(1);
+  }
+  &[data-size="small"] {
+    transform: translate(0, 17px) scale(1);
+  }
+  &[data-shrink] {
+    transform: translate(0, -1.5px) scale(0.75);
+    transform-origin: top left;
+    max-width: 133%;
+  }
+  &:not([data-disable-animation]) {
+    transition: ${theme.transitions.create(
+      ["color", "transform", "max-width"],
+      {
+        duration: theme.transitions.duration.shorter,
+        easing: theme.transitions.easing.easeOut,
+      },
+    )};
+  }
+  &[data-variant="filled"] {
+    z-index: 1;
+    pointer-events: none;
+    transform: translate(12px, 16px) scale(1);
+    max-width: calc(100% - 24px);
+    &[data-size="small"] {
+      transform: translate(12px, 13px) scale(1);
+    }
+    &[data-shrink] {
+      user-select: none;
+      pointer-events: auto;
+      transform: translate(12px, 7px) scale(0.75);
+      max-width: calc(133% - 24px);
+      &[data-size="small"] {
+        transform: translate(12px, 4px) scale(0.75);
+      }
+    }
+  }
+  &[data-variant="outlined"] {
+    z-index: 1;
+    pointer-events: none;
+    transform: translate(14px, 16px) scale(1);
+    max-width: calc(100% - 24px);
+    &[data-size="small"] {
+      transform: translate(14px, 9px) scale(1);
+    }
+    &[data-shrink] {
+      user-select: none;
+      pointer-events: auto;
+      transform: translate(14px, -9px) scale(0.75);
+      max-width: calc(133% - 24px);
+    }
+  }
+`;
+
+interface InputLabelProps {
+  color: Colors;
+  disableAnimation: boolean;
+  disabled: boolean;
+  error: boolean;
+  focused: boolean;
+  margin: boolean;
+  required: boolean;
+  shrink: boolean;
+  variant: "filled" | "outlined" | "standard";
+  children: ComponentChildren;
+}
+export function InputLabel(props: Partial<InputLabelProps>) {
+  const fcs = useFormControl(props);
+  return (
+    <FormLabel
+      data-form-control={!!fcs}
+      data-size={fcs.size}
+      data-shrink={props.shrink || fcs.filled || fcs.focused}
+      data-disable-animation={props.disableAnimation}
+      data-variant={fcs.variant}
+      class={root}
+      {...props}
+    />
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputOutlined.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputOutlined.tsx
new file mode 100644
index 00000000..3b40ffc7
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/InputOutlined.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function InputOutlined(): VNode {
+  return <div />;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
new file mode 100644
index 00000000..ba514571
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
@@ -0,0 +1,124 @@
+import { css } from "@linaria/core";
+import { h, VNode } from "preact";
+import { Colors, theme } from "../style";
+import { useFormControl } from "./FormControl";
+import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase";
+
+export interface Props {
+  autoComplete?: string;
+  autoFocus?: boolean;
+  color?: Colors;
+  defaultValue?: string;
+  disabled?: boolean;
+  disableUnderline?: boolean;
+  endAdornment?: VNode;
+  error?: boolean;
+  fullWidth?: boolean;
+  id?: string;
+  margin?: "dense" | "normal" | "none";
+  maxRows?: number;
+  minRows?: number;
+  multiline?: boolean;
+  name?: string;
+  onChange?: (s: string) => void;
+  placeholder?: string;
+  readOnly?: boolean;
+  required?: boolean;
+  rows?: number;
+  startAdornment?: VNode;
+  type?: string;
+  value?: string;
+}
+export function InputStandard({
+  type = "text",
+  multiline,
+  ...props
+}: Props): VNode {
+  const fcs = useFormControl(props);
+  return (
+    <InputBase
+      Root={Root}
+      Input={Input}
+      fullWidth={fcs.fullWidth}
+      multiline={multiline}
+      type={type}
+      {...props}
+    />
+  );
+}
+
+const rootStyle = css`
+  position: relative;
+`;
+const formControlStyle = css`
+  label + & {
+    margin-top: 16px;
+  }
+`;
+const underlineStyle = css`
+  &:after {
+    border-bottom: 2px solid var(--color-main);
+    left: 0px;
+    bottom: 0px;
+    content: "";
+    position: absolute;
+    right: 0px;
+    transform: scaleX(0);
+    transition: ${theme.transitions.create("transform", {
+      duration: theme.transitions.duration.shorter,
+      easing: theme.transitions.easing.easeOut,
+    })};
+    pointer-events: none;
+  }
+  &[data-focused]:after {
+    transform: scaleX(1);
+  }
+  &[data-error]:after {
+    border-bottom-color: ${theme.palette.error.main};
+    transform: scaleY(1);
+  }
+  &:before {
+    border-bottom: 1px solid
+      ${theme.palette.mode === "light"
+        ? "rgba(0, 0, 0, 0.42)"
+        : "rgba(255, 255, 255, 0.7)"};
+    left: 0px;
+    bottom: 0px;
+    right: 0px;
+    content: "\\00a0";
+    position: absolute;
+    transition: ${theme.transitions.create("border-bottom-color", {
+      duration: theme.transitions.duration.shorter,
+    })};
+    pointer-events: none;
+  }
+  &:hover:not([data-disabled]:before) {
+    border-bottom: 2px solid var(--color-main);
+    @media (hover: none) {
+      border-bottom: 1px solid
+        ${theme.palette.mode === "light"
+          ? "rgba(0, 0, 0, 0.42)"
+          : "rgba(255, 255, 255, 0.7)"};
+    }
+  }
+  &[data-disabled]:before {
+    border-bottom-style: solid;
+  }
+`;
+
+function Root({ disabled, focused, error, children }: any) {
+  return (
+    <InputBaseRoot
+      disabled={disabled}
+      focused={focused}
+      error={error}
+      class={[rootStyle, formControlStyle, underlineStyle].join(" ")}
+    >
+      {children}
+    </InputBaseRoot>
+  );
+}
+
+function Input(props: any) {
+  return <InputBaseComponent {...props} />;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/input/SelectFilled.tsx 
b/packages/taler-wallet-webextension/src/mui/input/SelectFilled.tsx
new file mode 100644
index 00000000..28b1859f
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/SelectFilled.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function SelectFilled(): VNode {
+  return <div />;
+}
diff --git 
a/packages/taler-wallet-webextension/src/mui/input/SelectOutlined.tsx 
b/packages/taler-wallet-webextension/src/mui/input/SelectOutlined.tsx
new file mode 100644
index 00000000..10ee4015
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/SelectOutlined.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function SelectOutlined(): VNode {
+  return <div />;
+}
diff --git 
a/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx 
b/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx
new file mode 100644
index 00000000..72cb635d
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function SelectStandard(): VNode {
+  return <div />;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx 
b/packages/taler-wallet-webextension/src/mui/style.tsx
index 5f9cd224..3fa3b7e3 100644
--- a/packages/taler-wallet-webextension/src/mui/style.tsx
+++ b/packages/taler-wallet-webextension/src/mui/style.tsx
@@ -12,6 +12,14 @@ import {
 } from "./colors/constants";
 import { getContrastRatio } from "./colors/manipulation";
 
+export type Colors =
+  | "primary"
+  | "secondary"
+  | "success"
+  | "error"
+  | "info"
+  | "warning";
+
 export function round(value: number): number {
   return Math.round(value * 1e5) / 1e5;
 }
@@ -386,6 +394,14 @@ function createTheme() {
       `,
       /* just of caseAllCaps */
       // button: buildVariant(fontWeightMedium, 14, 1.75, 0.4, caseAllCaps),
+
+      caption: css`
+        font-family: "Roboto", "Helvetica", "Arial", sans-serif;
+        font-weight: ${fontWeightMedium};
+        font-size: ${pxToRem(12)};
+        line-height: 1.66;
+        letter-spacing: ${round(0.4 / 12)}em;
+      `,
       // caption: buildVariant(fontWeightRegular, 12, 1.66, 0.4),
       // overline: buildVariant(fontWeightRegular, 12, 2.66, 1, caseAllCaps),
     };
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index f4df4f7f..e78bc4ff 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -57,7 +57,7 @@ function main(): void {
   }
 }
 
-setupI18n("en-US", strings);
+setupI18n("en", strings);
 
 if (document.readyState === "loading") {
   document.addEventListener("DOMContentLoaded", main);
diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
index a346df2c..9a1d8699 100644
--- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
@@ -73,7 +73,7 @@ function main(): void {
   }
 }
 
-setupI18n("en-US", strings);
+setupI18n("en", strings);
 
 if (document.readyState === "loading") {
   document.addEventListener("DOMContentLoaded", main);
@@ -102,188 +102,183 @@ function Application(): VNode {
   return (
     <TranslationProvider>
       <DevContextProvider>
-        {({ devMode }: { devMode: boolean }) => (
-          <IoCProviderForRuntime>
-            {/* <Match/> won't work in the first render if <Router /> is not 
called first */}
-            {/* https://github.com/preactjs/preact-router/issues/415 */}
-            <Router history={hash_history} />
-            <Match>
-              {({ path }: { path: string }) => {
-                if (path && path.startsWith("/cta")) return;
-                return (
-                  <Fragment>
-                    <LogoHeader />
-                    <WalletNavBar path={path} />
-                  </Fragment>
-                );
-              }}
-            </Match>
-            <div
-              style={{
-                backgroundColor: "lightcyan",
-                display: "flex",
-                justifyContent: "center",
-              }}
+        <IoCProviderForRuntime>
+          {/* <Match/> won't work in the first render if <Router /> is not 
called first */}
+          {/* https://github.com/preactjs/preact-router/issues/415 */}
+          <Router history={hash_history} />
+          <Match>
+            {({ path }: { path: string }) => {
+              if (path && path.startsWith("/cta")) return;
+              return (
+                <Fragment>
+                  <LogoHeader />
+                  <WalletNavBar path={path} />
+                </Fragment>
+              );
+            }}
+          </Match>
+          <div
+            style={{
+              backgroundColor: "lightcyan",
+              display: "flex",
+              justifyContent: "center",
+            }}
+          >
+            <PendingTransactions
+              goToTransaction={(txId: string) =>
+                route(Pages.balance_transaction.replace(":tid", txId))
+              }
+            />
+          </div>
+          <WalletBox>
+            {globalNotification && (
+              <SuccessBox onClick={clearNotification}>
+                <div>{globalNotification}</div>
+              </SuccessBox>
+            )}
+            <Router
+              history={hash_history}
+              onChange={clearNotificationWhenMovingOut}
             >
-              <PendingTransactions
-                goToTransaction={(txId: string) =>
-                  route(Pages.balance_transaction.replace(":tid", txId))
-                }
-              />
-            </div>
-            <WalletBox>
-              {globalNotification && (
-                <SuccessBox onClick={clearNotification}>
-                  <div>{globalNotification}</div>
-                </SuccessBox>
-              )}
-              <Router
-                history={hash_history}
-                onChange={clearNotificationWhenMovingOut}
-              >
-                <Route path={Pages.welcome} component={WelcomePage} />
+              <Route path={Pages.welcome} component={WelcomePage} />
 
-                {/**
-                 * BALANCE
-                 */}
+              {/**
+               * BALANCE
+               */}
 
-                <Route
-                  path={Pages.balance_history}
-                  component={HistoryPage}
-                  goToWalletDeposit={(currency: string) =>
-                    route(Pages.balance_deposit.replace(":currency", currency))
-                  }
-                  goToWalletManualWithdraw={(currency?: string) =>
-                    route(
-                      Pages.balance_manual_withdraw.replace(
-                        ":currency?",
-                        currency || "",
-                      ),
-                    )
-                  }
-                />
-                <Route
-                  path={Pages.balance_transaction}
-                  component={TransactionPage}
-                  goToWalletHistory={(currency?: string) => {
-                    route(
-                      Pages.balance_history.replace(
-                        ":currency",
-                        currency || "",
-                      ),
-                    );
-                  }}
-                />
+              <Route
+                path={Pages.balance_history}
+                component={HistoryPage}
+                goToWalletDeposit={(currency: string) =>
+                  route(Pages.balance_deposit.replace(":currency", currency))
+                }
+                goToWalletManualWithdraw={(currency?: string) =>
+                  route(
+                    Pages.balance_manual_withdraw.replace(
+                      ":currency?",
+                      currency || "",
+                    ),
+                  )
+                }
+              />
+              <Route
+                path={Pages.balance_transaction}
+                component={TransactionPage}
+                goToWalletHistory={(currency?: string) => {
+                  route(
+                    Pages.balance_history.replace(":currency", currency || ""),
+                  );
+                }}
+              />
 
-                <Route
-                  path={Pages.balance_manual_withdraw}
-                  component={ManualWithdrawPage}
-                  onCancel={() => {
-                    route(Pages.balance);
-                  }}
-                />
+              <Route
+                path={Pages.balance_manual_withdraw}
+                component={ManualWithdrawPage}
+                onCancel={() => {
+                  route(Pages.balance);
+                }}
+              />
 
-                <Route
-                  path={Pages.balance_deposit}
-                  component={DepositPage}
-                  onCancel={(currency: string) => {
-                    route(Pages.balance_history.replace(":currency", 
currency));
-                  }}
-                  onSuccess={(currency: string) => {
-                    route(Pages.balance_history.replace(":currency", 
currency));
-                    setGlobalNotification(
-                      <i18n.Translate>
-                        All done, your transaction is in progress
-                      </i18n.Translate>,
-                    );
-                  }}
-                />
-                {/**
-                 * PENDING
-                 */}
-                <Route path={Pages.settings} component={SettingsPage} />
+              <Route
+                path={Pages.balance_deposit}
+                component={DepositPage}
+                onCancel={(currency: string) => {
+                  route(Pages.balance_history.replace(":currency", currency));
+                }}
+                onSuccess={(currency: string) => {
+                  route(Pages.balance_history.replace(":currency", currency));
+                  setGlobalNotification(
+                    <i18n.Translate>
+                      All done, your transaction is in progress
+                    </i18n.Translate>,
+                  );
+                }}
+              />
+              {/**
+               * PENDING
+               */}
+              <Route path={Pages.settings} component={SettingsPage} />
 
-                {/**
-                 * BACKUP
-                 */}
-                <Route
-                  path={Pages.backup}
-                  component={BackupPage}
-                  onAddProvider={() => {
-                    route(Pages.backup_provider_add);
-                  }}
-                />
-                <Route
-                  path={Pages.backup_provider_detail}
-                  component={ProviderDetailPage}
-                  onBack={() => {
-                    route(Pages.backup);
-                  }}
-                />
-                <Route
-                  path={Pages.backup_provider_add}
-                  component={ProviderAddPage}
-                  onBack={() => {
-                    route(Pages.backup);
-                  }}
-                />
+              {/**
+               * BACKUP
+               */}
+              <Route
+                path={Pages.backup}
+                component={BackupPage}
+                onAddProvider={() => {
+                  route(Pages.backup_provider_add);
+                }}
+              />
+              <Route
+                path={Pages.backup_provider_detail}
+                component={ProviderDetailPage}
+                onBack={() => {
+                  route(Pages.backup);
+                }}
+              />
+              <Route
+                path={Pages.backup_provider_add}
+                component={ProviderAddPage}
+                onBack={() => {
+                  route(Pages.backup);
+                }}
+              />
 
-                {/**
-                 * SETTINGS
-                 */}
-                <Route
-                  path={Pages.settings_exchange_add}
-                  component={ExchangeAddPage}
-                  onBack={() => {
-                    route(Pages.balance);
-                  }}
-                />
+              {/**
+               * SETTINGS
+               */}
+              <Route
+                path={Pages.settings_exchange_add}
+                component={ExchangeAddPage}
+                onBack={() => {
+                  route(Pages.balance);
+                }}
+              />
 
-                {/**
-                 * DEV
-                 */}
+              {/**
+               * DEV
+               */}
 
-                <Route path={Pages.dev} component={DeveloperPage} />
+              <Route path={Pages.dev} component={DeveloperPage} />
 
-                {/**
-                 * CALL TO ACTION
-                 */}
-                <Route
-                  path={Pages.cta_pay}
-                  component={PayPage}
-                  goToWalletManualWithdraw={(currency?: string) =>
-                    route(
-                      Pages.balance_manual_withdraw.replace(
-                        ":currency?",
-                        currency || "",
-                      ),
-                    )
-                  }
-                  goBack={() => route(Pages.balance)}
-                />
-                <Route path={Pages.cta_refund} component={RefundPage} />
-                <Route path={Pages.cta_tips} component={TipPage} />
-                <Route path={Pages.cta_withdraw} component={WithdrawPage} />
+              {/**
+               * CALL TO ACTION
+               */}
+              <Route
+                path={Pages.cta_pay}
+                component={PayPage}
+                goToWalletManualWithdraw={(currency?: string) =>
+                  route(
+                    Pages.balance_manual_withdraw.replace(
+                      ":currency?",
+                      currency || "",
+                    ),
+                  )
+                }
+                goBack={() => route(Pages.balance)}
+              />
+              <Route path={Pages.cta_refund} component={RefundPage} />
+              <Route path={Pages.cta_tips} component={TipPage} />
+              <Route path={Pages.cta_withdraw} component={WithdrawPage} />
 
-                {/**
-                 * NOT FOUND
-                 * all redirects should be at the end
-                 */}
-                <Route
-                  path={Pages.balance}
-                  component={Redirect}
-                  to={Pages.balance_history.replace(":currency", "")}
-                />
+              {/**
+               * NOT FOUND
+               * all redirects should be at the end
+               */}
+              <Route
+                path={Pages.balance}
+                component={Redirect}
+                to={Pages.balance_history.replace(":currency", "")}
+              />
 
-                <Route
-                  default
-                  component={Redirect}
-                  to={Pages.balance_history.replace(":currency", "")}
-                />
-              </Router>
-            </WalletBox>
-          </IoCProviderForRuntime>
-        )}
+              <Route
+                default
+                component={Redirect}
+                to={Pages.balance_history.replace(":currency", "")}
+              />
+            </Router>
+          </WalletBox>
+        </IoCProviderForRuntime>
       </DevContextProvider>
     </TranslationProvider>
   );
diff --git a/packages/taler-wallet-webextension/static/img/delete_24px.svg 
b/packages/taler-wallet-webextension/static/img/delete_24px.svg
new file mode 100644
index 00000000..0d0b74d1
--- /dev/null
+++ b/packages/taler-wallet-webextension/static/img/delete_24px.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; viewBox="0 0 24 24"><path d="M0 
0h24v24H0z" fill="none"/><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 
2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/static/img/send_24px.svg 
b/packages/taler-wallet-webextension/static/img/send_24px.svg
new file mode 100644
index 00000000..95fe7a4c
--- /dev/null
+++ b/packages/taler-wallet-webextension/static/img/send_24px.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; viewBox="0 0 24 24"><path d="M0 
0h24v24H0z" fill="none"/><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
\ No newline at end of file

-- 
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]