aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-03-10 23:13:10 -0300
committerSebastian <sebasjm@gmail.com>2022-03-10 23:14:10 -0300
commit2150f3d96b25772dd608e245cd3508f857478c5b (patch)
tree7f449ec4df0f90c46774d1934ebee2eabb52cec7
parent60a50babd14de6efbe16d9b427af85acc9da76e9 (diff)
grid implementation
-rw-r--r--packages/taler-wallet-webextension/src/components/Banner.stories.tsx54
-rw-r--r--packages/taler-wallet-webextension/src/components/Banner.tsx49
-rw-r--r--packages/taler-wallet-webextension/src/components/styled/index.tsx10
-rw-r--r--packages/taler-wallet-webextension/src/mui/Avatar.tsx52
-rw-r--r--packages/taler-wallet-webextension/src/mui/Button.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/mui/Grid.stories.tsx192
-rw-r--r--packages/taler-wallet-webextension/src/mui/Grid.tsx244
-rw-r--r--packages/taler-wallet-webextension/src/mui/Paper.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/mui/Typography.tsx89
-rw-r--r--packages/taler-wallet-webextension/src/mui/style.tsx78
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 000000000..136302166
--- /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 6ff7b1019..f6af81184 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 a5ed64a83..80bfaa549 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 963984ab6..d5bd9d421 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 b197ca26a..f3272a57b 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 000000000..3c9361326
--- /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 3974e3c2e..ccabed060 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 52524380b..00eeda324 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 4fc614463..830f1005a 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 84b0538be..e2af05c49 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,
};
}