gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: grid implementation


From: gnunet
Subject: [taler-wallet-core] branch master updated: grid implementation
Date: Fri, 11 Mar 2022 03:14:18 +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 2150f3d9 grid implementation
2150f3d9 is described below

commit 2150f3d96b25772dd608e245cd3508f857478c5b
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Mar 10 23:13:10 2022 -0300

    grid implementation
---
 .../src/components/Banner.stories.tsx              |  54 +++++
 .../src/components/Banner.tsx                      |  49 ++++-
 .../src/components/styled/index.tsx                |  10 +
 .../taler-wallet-webextension/src/mui/Avatar.tsx   |  52 ++++-
 .../taler-wallet-webextension/src/mui/Button.tsx   |   2 +-
 .../src/mui/Grid.stories.tsx                       | 192 ++++++++++++++++
 .../taler-wallet-webextension/src/mui/Grid.tsx     | 244 ++++++++++++++++++++-
 .../taler-wallet-webextension/src/mui/Paper.tsx    |   2 +-
 .../src/mui/Typography.tsx                         |  89 +++++++-
 .../taler-wallet-webextension/src/mui/style.tsx    |  78 ++++++-
 10 files changed, 744 insertions(+), 28 deletions(-)

diff --git 
a/packages/taler-wallet-webextension/src/components/Banner.stories.tsx 
b/packages/taler-wallet-webextension/src/components/Banner.stories.tsx
new file mode 100644
index 00000000..13630216
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/Banner.stories.tsx
@@ -0,0 +1,54 @@
+/*
+ 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 { Banner } from "./Banner";
+import { Fragment, h } from "preact";
+
+export default {
+  title: "mui/banner",
+  component: Banner,
+};
+
+function Wrapper({ children }: any) {
+  return (
+    <div
+      style={{
+        display: "flex",
+        backgroundColor: "lightgray",
+        padding: 10,
+        width: "100%",
+        // width: 400,
+        // height: 400,
+        justifyContent: "center",
+      }}
+    >
+      <div style={{ flexGrow: 1 }}>{children}</div>
+    </div>
+  );
+}
+
+export const BasicExample = () => (
+  <Fragment>
+    <Wrapper>
+      <Banner />
+    </Wrapper>
+  </Fragment>
+);
diff --git a/packages/taler-wallet-webextension/src/components/Banner.tsx 
b/packages/taler-wallet-webextension/src/components/Banner.tsx
index 6ff7b101..f6af8118 100644
--- a/packages/taler-wallet-webextension/src/components/Banner.tsx
+++ b/packages/taler-wallet-webextension/src/components/Banner.tsx
@@ -1,33 +1,58 @@
 import { h, Fragment, VNode } from "preact";
 import { Divider } from "../mui/Divider";
-import { Button } from "./styled/index.js";
+import { Button } from "../mui/Button";
 import { Typography } from "../mui/Typography";
 import { Avatar } from "../mui/Avatar";
 import { Grid } from "../mui/Grid";
 import { Paper } from "../mui/Paper";
+import { Icon } from "./styled";
+import settingsIcon from "../../static/img/settings_black_24dp.svg";
+// & > a > div.settings-icon {
+//   mask: url(${settingsIcon}) no-repeat center;
+//   background-color: white;
+//   width: 24px;
+//   height: 24px;
+//   margin-left: auto;
+//   margin-right: 8px;
+//   padding: 4px;
+// }
+// & > a.active {
+//   background-color: #f8faf7;
+//   color: #0042b2;
+//   font-weight: bold;
+// }
+// & > a.active > div.settings-icon {
+//   background-color: #0042b2;
+// }
 
-function SignalWifiOffIcon(): VNode {
-  return <Fragment />;
+function SignalWifiOffIcon({ ...rest }: any): VNode {
+  return <Icon {...rest} />;
 }
 
-function Banner({}: {}) {
+export function Banner({}: {}) {
   return (
     <Fragment>
-      <Paper elevation={0} /*className={classes.paper}*/>
-        <Grid container wrap="nowrap" spacing={16} alignItems="center">
-          <Grid item>
-            <Avatar /*className={classes.avatar}*/>
-              <SignalWifiOffIcon />
+      <Paper elevation={3} /*className={classes.paper}*/>
+        <Grid
+          container
+          // wrap="nowrap"
+          // spacing={10}
+          alignItems="center"
+          columns={3}
+        >
+          <Grid item xs={1}>
+            <Avatar>
+              <SignalWifiOffIcon style={{ backgroundColor: "red" }} />
             </Avatar>
           </Grid>
-          <Grid item>
+          <Grid item xs={1}>
             <Typography>
               You have lost connection to the internet. This app is offline.
             </Typography>
           </Grid>
         </Grid>
-        <Grid container justify="flex-end" spacing={8}>
-          <Grid item>
+        <Grid container justifyContent="flex-end" spacing={8} columns={3}>
+          <Grid item xs={1}>
             <Button color="primary">Turn on wifi</Button>
           </Grid>
         </Grid>
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx 
b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index a5ed64a8..80bfaa54 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -826,6 +826,16 @@ export const NavigationHeader = styled.div`
   }
 `;
 
+export const Icon = styled.div`
+  mask: url(${settingsIcon}) no-repeat center;
+  background-color: gray;
+  width: 24px;
+  height: 24px;
+  margin-left: auto;
+  margin-right: 8px;
+  padding: 4px;
+`;
+
 const image = `url("data:image/svg+xml,%3csvg 
xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath 
stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' 
stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`;
 
 export const NiceSelect = styled.div`
diff --git a/packages/taler-wallet-webextension/src/mui/Avatar.tsx 
b/packages/taler-wallet-webextension/src/mui/Avatar.tsx
index 963984ab..d5bd9d42 100644
--- a/packages/taler-wallet-webextension/src/mui/Avatar.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Avatar.tsx
@@ -1,5 +1,53 @@
+import { css } from "@linaria/core";
 import { h, Fragment, VNode, ComponentChildren } from "preact";
+import { theme } from "./style";
 
-export function Avatar({}: { children: ComponentChildren }): VNode {
-  return <Fragment />;
+const root = css`
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  width: 40px;
+  height: 40px;
+  font-family: ${theme.typography.fontFamily};
+  font-size: ${theme.typography.pxToRem(20)};
+  line-height: 1;
+  overflow: hidden;
+  user-select: none;
+`;
+
+const colorStyle = css`
+  color: ${theme.palette.background.default};
+  background-color: ${theme.palette.mode === "light"
+    ? theme.palette.grey[400]
+    : theme.palette.grey[600]};
+`;
+
+const avatarImageStyle = css`
+  width: 100%;
+  height: 100%;
+  text-align: center;
+  object-fit: cover;
+  color: transparent;
+  text-indent: 10000;
+`;
+
+interface Props {
+  variant?: "circular" | "rounded" | "square";
+  children?: ComponentChildren;
+}
+
+export function Avatar({ variant, children, ...rest }: Props): VNode {
+  const borderStyle =
+    variant === "square"
+      ? theme.shape.squareBorder
+      : variant === "rounded"
+      ? theme.shape.roundBorder
+      : theme.shape.circularBorder;
+  return (
+    <div class={[root, borderStyle].join(" ")} {...rest}>
+      {children}
+    </div>
+  );
 }
diff --git a/packages/taler-wallet-webextension/src/mui/Button.tsx 
b/packages/taler-wallet-webextension/src/mui/Button.tsx
index b197ca26..f3272a57 100644
--- a/packages/taler-wallet-webextension/src/mui/Button.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Button.tsx
@@ -185,7 +185,7 @@ export function Button({
       disabled={disabled}
       class={[
         theme.typography.button,
-        theme.shape.borderRadius,
+        theme.shape.roundBorder,
         ripple,
         baseStyle,
         button,
diff --git a/packages/taler-wallet-webextension/src/mui/Grid.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/Grid.stories.tsx
new file mode 100644
index 00000000..3c936132
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/Grid.stories.tsx
@@ -0,0 +1,192 @@
+/*
+ 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 { Grid } from "./Grid";
+import { Fragment, h } from "preact";
+
+export default {
+  title: "mui/grid",
+  component: Grid,
+};
+
+function Item({ children }: any) {
+  return (
+    <div
+      style={{
+        padding: 10,
+        backgroundColor: "white",
+        textAlign: "center",
+        color: "back",
+      }}
+    >
+      {children}
+    </div>
+  );
+}
+
+function Wrapper({ children }: any) {
+  return (
+    <div
+      style={{
+        display: "flex",
+        backgroundColor: "lightgray",
+        padding: 10,
+        width: "100%",
+        // width: 400,
+        // height: 400,
+        justifyContent: "center",
+      }}
+    >
+      <div style={{ flexGrow: 1 }}>{children}</div>
+    </div>
+  );
+}
+
+export const BasicExample = () => (
+  <Fragment>
+    <Wrapper>
+      <Grid container spacing={2}>
+        <Grid item xs={8}>
+          <Item>xs=8</Item>
+        </Grid>
+        <Grid item xs={4}>
+          <Item>xs=4</Item>
+        </Grid>
+        <Grid item xs={4}>
+          <Item>xs=4</Item>
+        </Grid>
+        <Grid item xs={8}>
+          <Item>xs=8</Item>
+        </Grid>
+      </Grid>
+    </Wrapper>
+    <Wrapper>
+      <Grid container spacing={2}>
+        <Grid item xs={6} md={8}>
+          <Item>xs=6 md=8</Item>
+        </Grid>
+        <Grid item xs={6} md={4}>
+          <Item>xs=6 md=4</Item>
+        </Grid>
+        <Grid item xs={6} md={4}>
+          <Item>xs=6 md=4</Item>
+        </Grid>
+        <Grid item xs={6} md={8}>
+          <Item>xs=6 md=8</Item>
+        </Grid>
+      </Grid>
+    </Wrapper>
+  </Fragment>
+);
+
+export const Responsive12ColumnsSize = () => (
+  <Fragment>
+    <Wrapper>
+      <p>Item size is responsive: xs=6 sm=4 md=2</p>
+      <Grid container spacing={1} columns={12}>
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} sm={4} md={2} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+    <Wrapper>
+      <p>Item size is fixed</p>
+      <Grid container spacing={1} columns={12}>
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+  </Fragment>
+);
+
+export const Responsive12Spacing = () => (
+  <Fragment>
+    <Wrapper>
+      <p>Item space is responsive: xs=1 sm=2 md=3</p>
+      <Grid container spacing={{ xs: 2, sm: 4, md: 6 }} columns={12}>
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+    <Wrapper>
+      <p>Item space is fixed</p>
+      <Grid container spacing={1} columns={12}>
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+
+    <Wrapper>
+      <p>Item row space is responsive: xs=6 sm=4 md=1</p>
+      <Grid
+        container
+        rowSpacing={{ xs: 6, sm: 3, md: 1 }}
+        columnSpacing={1}
+        columns={12}
+      >
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+    <Wrapper>
+      <p>Item col space is responsive: xs=6 sm=3 md=1</p>
+      <Grid
+        container
+        columnSpacing={{ xs: 6, sm: 3, md: 1 }}
+        rowSpacing={1}
+        columns={12}
+      >
+        {Array.from(Array(6)).map((_, index) => (
+          <Grid item xs={6} key={index}>
+            <Item>item {index}</Item>
+          </Grid>
+        ))}
+      </Grid>
+    </Wrapper>
+  </Fragment>
+);
+
+export const Example = () => (
+  <Wrapper>
+    <p>Item row space is responsive: xs=6 sm=4 md=1</p>
+    <Grid container rowSpacing={3} columnSpacing={1} columns={12}>
+      {Array.from(Array(6)).map((_, index) => (
+        <Grid item xs={6} key={index}>
+          <Item>item {index}</Item>
+        </Grid>
+      ))}
+    </Grid>
+  </Wrapper>
+);
diff --git a/packages/taler-wallet-webextension/src/mui/Grid.tsx 
b/packages/taler-wallet-webextension/src/mui/Grid.tsx
index 3974e3c2..ccabed06 100644
--- a/packages/taler-wallet-webextension/src/mui/Grid.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Grid.tsx
@@ -1,13 +1,241 @@
-import { h, Fragment, VNode, ComponentChildren } from "preact";
+import { css } from "@linaria/core";
+import { h, Fragment, VNode, ComponentChildren, createContext } from "preact";
+import { useContext } from "preact/hooks";
+import { theme } from "./style";
 
-export function Grid({}: {
+type ResponsiveKeys = "xs" | "sm" | "md" | "lg" | "xl";
+
+export type ResponsiveSize = {
+  xs: number;
+  sm: number;
+  md: number;
+  lg: number;
+  xl: number;
+};
+
+const root = css`
+  box-sizing: border-box;
+`;
+const containerStyle = css`
+  display: flex;
+  flex-wrap: wrap;
+  width: 100%;
+`;
+const itemStyle = css`
+  margin: 0;
+`;
+const zeroMinWidthStyle = css`
+  min-width: 0px;
+`;
+
+type GridSizes = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
+type SpacingSizes = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
+
+export interface Props {
+  columns?: number | Partial<ResponsiveSize>;
   container?: boolean;
-  wrap?: string;
   item?: boolean;
-  spacing?: number;
-  alignItems?: string;
-  justify?: string;
+
+  direction?: "column-reverse" | "column" | "row-reverse" | "row";
+
+  lg?: GridSizes | "auto" | "true";
+  md?: GridSizes | "auto" | "true";
+  sm?: GridSizes | "auto" | "true";
+  xl?: GridSizes | "auto" | "true";
+  xs?: GridSizes | "auto" | "true";
+
+  wrap?: "nowrap" | "wrap-reverse" | "wrap";
+  spacing?: SpacingSizes | Partial<ResponsiveSize>;
+  columnSpacing?: SpacingSizes | Partial<ResponsiveSize>;
+  rowSpacing?: SpacingSizes | Partial<ResponsiveSize>;
+
+  alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
+  justifyContent?:
+    | "flex-start"
+    | "flex-end"
+    | "center"
+    | "space-around"
+    | "space-between"
+    | "space-evenly";
+
+  zeroMinWidth?: boolean;
   children: ComponentChildren;
-}): VNode {
-  return <Fragment />;
+}
+theme.breakpoints.up;
+
+function getOffset(val: number | string) {
+  if (typeof val === "number") `${val}px`;
+  return val;
+}
+
+const columnGapVariant = css`
+  ${theme.breakpoints.up("xs")} {
+    width: calc(100% + var(--space-col-xs));
+    margin-left: calc(-1 * var(--space-col-xs));
+    & > div {
+      padding-left: var(--space-col-xs);
+    }
+  }
+  ${theme.breakpoints.up("sm")} {
+    width: calc(100% + var(--space-col-sm));
+    margin-left: calc(-1 * var(--space-col-sm));
+    & > div {
+      padding-left: var(--space-col-sm);
+    }
+  }
+  ${theme.breakpoints.up("md")} {
+    width: calc(100% + var(--space-col-md));
+    margin-left: calc(-1 * var(--space-col-md));
+    & > div {
+      padding-left: var(--space-col-md);
+    }
+  }
+`;
+const rowGapVariant = css`
+  ${theme.breakpoints.up("xs")} {
+    margin-top: calc(-1 * var(--space-row-xs));
+    & > div {
+      padding-top: var(--space-row-xs);
+    }
+  }
+  ${theme.breakpoints.up("sm")} {
+    margin-top: calc(-1 * var(--space-row-sm));
+    & > div {
+      padding-top: var(--space-row-sm);
+    }
+  }
+  ${theme.breakpoints.up("md")} {
+    margin-top: calc(-1 * var(--space-row-md));
+    & > div {
+      padding-top: var(--space-row-md);
+    }
+  }
+`;
+
+const sizeVariant = css`
+  ${theme.breakpoints.up("xs")} {
+    flex-basis: var(--relation-col-vs-xs);
+    flex-grow: 0;
+    max-width: var(--relation-col-vs-xs);
+  }
+  ${theme.breakpoints.up("sm")} {
+    flex-basis: var(--relation-col-vs-sm);
+    flex-grow: 0;
+    max-width: var(--relation-col-vs-sm);
+  }
+  ${theme.breakpoints.up("md")} {
+    flex-basis: var(--relation-col-vs-md);
+    flex-grow: 0;
+    max-width: var(--relation-col-vs-md);
+  }
+`;
+
+const GridContext = createContext<ResponsiveSize>(toResponsive(12));
+
+function toResponsive(v: number | Partial<ResponsiveSize>): ResponsiveSize {
+  const p = typeof v === "number" ? { xs: v } : v;
+  const xs = p.xs || 12;
+  const sm = p.sm || xs;
+  const md = p.md || sm;
+  const lg = p.lg || md;
+  const xl = p.xl || lg;
+  return {
+    xs,
+    sm,
+    md,
+    lg,
+    xl,
+  };
+}
+
+export function Grid({
+  columns: cp,
+  container = false,
+  item = false,
+  direction = "row",
+  lg,
+  md,
+  sm,
+  xl,
+  xs,
+  wrap = "wrap",
+  spacing = 0,
+  columnSpacing: csp,
+  rowSpacing: rsp,
+  alignItems,
+  justifyContent,
+  zeroMinWidth = false,
+  children,
+}: Props): VNode {
+  const cc = useContext(GridContext);
+  const columns = !cp ? cc : toResponsive(cp);
+
+  const rowSpacing = rsp ? toResponsive(rsp) : toResponsive(spacing);
+  const columnSpacing = csp ? toResponsive(csp) : toResponsive(spacing);
+
+  const ssize = toResponsive({ xs, md, lg, xl, sm } as any);
+
+  if (container) {
+    console.log(rowSpacing);
+    console.log(columnSpacing);
+  }
+  const spacingStyles = !container
+    ? {}
+    : {
+        "--space-col-xs": getOffset(theme.spacing(columnSpacing.xs)),
+        "--space-col-sm": getOffset(theme.spacing(columnSpacing.sm)),
+        "--space-col-md": getOffset(theme.spacing(columnSpacing.md)),
+        "--space-col-lg": getOffset(theme.spacing(columnSpacing.lg)),
+        "--space-col-xl": getOffset(theme.spacing(columnSpacing.xl)),
+
+        "--space-row-xs": getOffset(theme.spacing(rowSpacing.xs)),
+        "--space-row-sm": getOffset(theme.spacing(rowSpacing.sm)),
+        "--space-row-md": getOffset(theme.spacing(rowSpacing.md)),
+        "--space-row-lg": getOffset(theme.spacing(rowSpacing.lg)),
+        "--space-row-xl": getOffset(theme.spacing(rowSpacing.xl)),
+      };
+  const relationStyles = !item
+    ? {}
+    : {
+        "--relation-col-vs-sm": relation(columns, ssize, "sm"),
+        "--relation-col-vs-lg": relation(columns, ssize, "lg"),
+        "--relation-col-vs-xs": relation(columns, ssize, "xs"),
+        "--relation-col-vs-xl": relation(columns, ssize, "xl"),
+        "--relation-col-vs-md": relation(columns, ssize, "md"),
+      };
+
+  return (
+    <GridContext.Provider value={columns}>
+      <div
+        id={container ? "container" : "item"}
+        class={[
+          root,
+          container && containerStyle,
+          item && itemStyle,
+          zeroMinWidth && zeroMinWidthStyle,
+          sizeVariant,
+          container && columnGapVariant,
+          container && rowGapVariant,
+        ].join(" ")}
+        style={{
+          ...relationStyles,
+          ...spacingStyles,
+          justifyContent,
+          alignItems,
+        }}
+      >
+        {children}
+      </div>
+    </GridContext.Provider>
+  );
+}
+function relation(
+  cols: ResponsiveSize,
+  values: ResponsiveSize,
+  size: ResponsiveKeys,
+) {
+  const colsNum = typeof cols === "number" ? cols : cols[size] || 12;
+  return (
+    String(Math.round(((values[size] || 1) / colsNum) * 10e7) / 10e5) + "%"
+  );
 }
diff --git a/packages/taler-wallet-webextension/src/mui/Paper.tsx 
b/packages/taler-wallet-webextension/src/mui/Paper.tsx
index 52524380..00eeda32 100644
--- a/packages/taler-wallet-webextension/src/mui/Paper.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Paper.tsx
@@ -35,7 +35,7 @@ export function Paper({
     <div
       class={[
         baseStyle,
-        !square && theme.shape.borderRadius,
+        !square && theme.shape.roundBorder,
         borderVariant[variant],
       ].join(" ")}
       style={{
diff --git a/packages/taler-wallet-webextension/src/mui/Typography.tsx 
b/packages/taler-wallet-webextension/src/mui/Typography.tsx
index 4fc61446..830f1005 100644
--- a/packages/taler-wallet-webextension/src/mui/Typography.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Typography.tsx
@@ -1,9 +1,92 @@
+import { css } from "@linaria/core";
 import { h, Fragment, VNode, ComponentChildren } from "preact";
 
+type VariantEnum =
+  | "body1"
+  | "body2"
+  | "button"
+  | "caption"
+  | "h1"
+  | "h2"
+  | "h3"
+  | "h4"
+  | "h5"
+  | "h6"
+  | "inherit"
+  | "overline"
+  | "subtitle1"
+  | "subtitle2";
+
 interface Props {
-  children: ComponentChildren;
+  align?: "center" | "inherit" | "justify" | "left" | "right";
+  gutterBottom?: boolean;
+  noWrap?: boolean;
+  paragraph?: boolean;
+  variant?: VariantEnum;
+  children?: ComponentChildren;
 }
 
-export function Typography({ children }: Props): VNode {
-  return <p>{children}</p>;
+const defaultVariantMapping = {
+  h1: "h1",
+  h2: "h2",
+  h3: "h3",
+  h4: "h4",
+  h5: "h5",
+  h6: "h6",
+  subtitle1: "h6",
+  subtitle2: "h6",
+  body1: "p",
+  body2: "p",
+  inherit: "p",
+};
+
+const root = css`
+  margin: 0;
+`;
+
+const noWrapStyle = css`
+  overflow: "hidden";
+  text-overflow: "ellipsis";
+  white-space: "nowrap";
+`;
+const gutterBottomStyle = css`
+  margin-bottom: 0.35em;
+`;
+const paragraphStyle = css`
+  margin-bottom: 16px;
+`;
+
+export function Typography({
+  align,
+  gutterBottom = false,
+  noWrap = false,
+  paragraph = false,
+  variant = "body1",
+  children,
+}: Props): VNode {
+  const cmp = paragraph
+    ? "p"
+    : defaultVariantMapping[variant as "h1"] || "span";
+
+  const alignStyle =
+    align == "inherit"
+      ? {}
+      : {
+          textAlign: align,
+        };
+  return h(
+    cmp,
+    {
+      class: [
+        root,
+        noWrap && noWrapStyle,
+        gutterBottom && gutterBottomStyle,
+        paragraph && paragraphStyle,
+      ].join(" "),
+      style: {
+        ...alignStyle,
+      },
+    },
+    children,
+  );
 }
diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx 
b/packages/taler-wallet-webextension/src/mui/style.tsx
index 84b0538b..e2af05c4 100644
--- a/packages/taler-wallet-webextension/src/mui/style.tsx
+++ b/packages/taler-wallet-webextension/src/mui/style.tsx
@@ -22,6 +22,14 @@ export function pxToRem(size: number): string {
   return `${(size / htmlFontSize) * coef}rem`;
 }
 
+export interface Spacing {
+  (): string;
+  (value: number): string;
+  (topBottom: number, rightLeft: number): string;
+  (top: number, rightLeft: number, bottom: number): string;
+  (top: number, right: number, bottom: number, left: number): string;
+}
+
 export const theme = createTheme();
 
 export const ripple = css`
@@ -117,11 +125,78 @@ function createTheme() {
   const shadows = createAllShadows();
   const transitions = createTransitions({});
   const breakpoints = createBreakpoints({});
+  const spacing = createSpacing();
   const shape = {
-    borderRadius: css`
+    roundBorder: css`
       border-radius: 4px;
     `,
+    squareBorder: css`
+      border-radius: 0px;
+    `,
+    circularBorder: css`
+      border-radius: 50%;
+    `,
   };
+
+  /////////////////////
+  ///////////////////// SPACING
+  /////////////////////
+
+  function createUnaryUnit(theme: { spacing: number }, defaultValue: number) {
+    const themeSpacing = theme.spacing || defaultValue;
+
+    if (typeof themeSpacing === "number") {
+      return (abs: number | string) => {
+        if (typeof abs === "string") {
+          return abs;
+        }
+
+        return themeSpacing * abs;
+      };
+    }
+
+    if (Array.isArray(themeSpacing)) {
+      return (abs: number | string) => {
+        if (typeof abs === "string") {
+          return abs;
+        }
+
+        return themeSpacing[abs];
+      };
+    }
+
+    if (typeof themeSpacing === "function") {
+      return themeSpacing;
+    }
+
+    return (a: string | number) => "";
+  }
+
+  function createUnarySpacing(theme: { spacing: number }) {
+    return createUnaryUnit(theme, 8);
+  }
+
+  function createSpacing(spacingInput: number = 8): Spacing {
+    // Material Design layouts are visually balanced. Most measurements align 
to an 8dp grid, which aligns both spacing and the overall layout.
+    // Smaller components, such as icons, can align to a 4dp grid.
+    // https://material.io/design/layout/understanding-layout.html#usage
+    const transform = createUnarySpacing({
+      spacing: spacingInput,
+    });
+
+    const spacing = (...argsInput: ReadonlyArray<number | string>): string => {
+      const args = argsInput.length === 0 ? [1] : argsInput;
+
+      return args
+        .map((argument) => {
+          const output = transform(argument);
+          return typeof output === "number" ? `${output}px` : output;
+        })
+        .join(" ");
+    };
+
+    return spacing;
+  }
   /////////////////////
   ///////////////////// BREAKPOINTS
   /////////////////////
@@ -691,6 +766,7 @@ function createTheme() {
     shape,
     transitions,
     breakpoints,
+    spacing,
     pxToRem,
   };
 }

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