migration css to linaria

This commit is contained in:
Sebastian 2021-07-09 23:15:49 -03:00
parent 5881d957ca
commit d29499b80a
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
11 changed files with 1579 additions and 136 deletions

View File

@ -1,2 +1,3 @@
extension/ extension/
/storybook-static/ /storybook-static/
/.linaria-cache/

View File

@ -21,6 +21,6 @@
{ {
//FIXME: check if we can remove this preset and just use default storybook presets //FIXME: check if we can remove this preset and just use default storybook presets
"presets": [ "presets": [
"preact-cli/babel" "preact-cli/babel",
] ]
} }

View File

@ -40,8 +40,9 @@ module.exports = {
'@babel/preset-react', { '@babel/preset-react', {
runtime: 'automatic', runtime: 'automatic',
}, },
'preset-react-jsx-transform' 'preset-react-jsx-transform'
], ],
"@linaria",
], ],
}), }),
webpackFinal: (config) => { webpackFinal: (config) => {
@ -51,6 +52,30 @@ module.exports = {
react: "preact/compat", react: "preact/compat",
"react-dom": "preact/compat", "react-dom": "preact/compat",
}; };
// we need to add @linaria loader AFTER the babel-loader
// https://github.com/callstack/linaria/blob/master/docs/BUNDLERS_INTEGRATION.md#webpack
config.module.rules[0] = {
...(config.module.rules[0]),
loader: undefined, // Disable the predefined babel-loader on the rule
use: [
{
...(config.module.rules[0].use[0]),
loader: 'babel-loader',
},
{
loader: '@linaria/webpack-loader',
options: {
sourceMap: true, //always true since this is dev
babelOptions: {
presets: config.module.rules[0].use[0].options.presets,
}
// Pass the current babel options to linaria's babel instance
}
}
]
};
return config; return config;
}, },
} }

View File

@ -27,6 +27,15 @@
"@babel/core": "^7.14.0", "@babel/core": "^7.14.0",
"@babel/plugin-transform-react-jsx-source": "^7.12.13", "@babel/plugin-transform-react-jsx-source": "^7.12.13",
"@babel/preset-typescript": "^7.13.0", "@babel/preset-typescript": "^7.13.0",
"@linaria/babel-preset": "^3.0.0-beta.4",
"@linaria/core": "^3.0.0-beta.4",
"@linaria/react": "^3.0.0-beta.7",
"@linaria/rollup": "^3.0.0-beta.7",
"@linaria/shaker": "^3.0.0-beta.7",
"@linaria/webpack-loader": "^3.0.0-beta.7",
"@rollup/plugin-alias": "^3.1.2",
"@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-image": "^2.0.6", "@rollup/plugin-image": "^2.0.6",
"@rollup/plugin-json": "^4.1.0", "@rollup/plugin-json": "^4.1.0",
@ -41,6 +50,7 @@
"@types/jest": "^26.0.23", "@types/jest": "^26.0.23",
"@types/node": "^14.14.22", "@types/node": "^14.14.22",
"ava": "3.15.0", "ava": "3.15.0",
"babel-loader": "^8.2.2",
"babel-plugin-transform-react-jsx": "^6.24.1", "babel-plugin-transform-react-jsx": "^6.24.1",
"enzyme": "^3.11.0", "enzyme": "^3.11.0",
"enzyme-adapter-preact-pure": "^3.1.0", "enzyme-adapter-preact-pure": "^3.1.0",
@ -51,6 +61,7 @@
"preact-render-to-string": "^5.1.19", "preact-render-to-string": "^5.1.19",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.37.1", "rollup": "^2.37.1",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-ignore": "^1.0.9", "rollup-plugin-ignore": "^1.0.9",
"rollup-plugin-sourcemaps": "^0.6.3", "rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",

View File

@ -6,8 +6,18 @@ import builtins from "builtin-modules";
import replace from "@rollup/plugin-replace"; import replace from "@rollup/plugin-replace";
import ignore from "rollup-plugin-ignore" import ignore from "rollup-plugin-ignore"
import image from '@rollup/plugin-image'; import image from '@rollup/plugin-image';
import linaria from '@linaria/rollup';
import css from 'rollup-plugin-css-only';
import alias from '@rollup/plugin-alias';
const makePlugins = () => [ const makePlugins = () => [
alias({
entries: [
{ find: 'react', replacement: 'preact/compat' },
{ find: 'react-dom', replacement: 'preact/compat' }
]
}),
ignore(["module", "os"]), ignore(["module", "os"]),
nodeResolve({ nodeResolve({
browser: true, browser: true,
@ -31,6 +41,14 @@ const makePlugins = () => [
json(), json(),
image(), image(),
linaria({
sourceMap: process.env.NODE_ENV !== 'production',
}),
css({
output: 'styles.css',
}),
]; ];

View File

@ -0,0 +1,135 @@
// import { FunctionalComponent, JSX } from 'preact';
// import styled from './preact-styled'
// import { css } from '@linaria/core';
import { styled } from '@linaria/react';
export const PopupBox = styled.div`
height: calc(320px - 34px - 16px);
display: flex;
flex-direction: column;
& > section {
overflow: auto;
}
& > footer {
padding-top: 5px;
flex-direction: row;
justify-content: flex-end;
display: flex;
& > button {
margin-left: 5px;
}
}
`
const Button = styled.button`
display: inline-block;
zoom: 1;
line-height: normal;
white-space: nowrap;
vertical-align: middle;
text-align: center;
cursor: pointer;
user-select: none;
box-sizing: border-box;
font-family: inherit;
font-size: 100%;
padding: 0.5em 1em;
color: #444; /* rgba not supported (IE 8) */
color: rgba(0, 0, 0, 0.8); /* rgba supported */
border: 1px solid #999; /*IE 6/7/8*/
border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
background-color: '#e6e6e6';
text-decoration: none;
border-radius: 2px;
:focus {
outline: 0;
}
[disabled] {
border: none;
background-image: none;
/* csslint ignore:start */
filter: alpha(opacity=40);
/* csslint ignore:end */
opacity: 0.4;
cursor: not-allowed;
box-shadow: none;
pointer-events: none;
}
:hover {
filter: alpha(opacity=90);
background-image: linear-gradient(
transparent,
rgba(0, 0, 0, 0.05) 40%,
rgba(0, 0, 0, 0.1)
);
}
`;
const ButtonVariant = styled(Button)`
color: white;
border-radius: 4px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
`
export const ButtonPrimary = styled(ButtonVariant)`
background-color: rgb(66, 184, 221);
`
export const ButtonSuccess = styled(ButtonVariant)`
background-color: rgb(28, 184, 65);
`
export const ButtonWarning = styled(ButtonVariant)`
background-color: rgb(223, 117, 20);
`
export const ButtonDestructive = styled(ButtonVariant)`
background-color: rgb(202, 60, 60);
`
export const BoldLight = styled.div`
color: gray;
font-weight: bold;
`
export const Centered = styled.div`
text-align: center;
& > :not(:first-child) {
margin-top: 15px;
}
`
export const Row = styled.div`
display: flex;
border: 1px solid gray;
border-radius: 0.5em;
margin: 0.5em 0;
justify-content: space-between;
padding: 0.5em;
`
export const SmallText = styled.div`
font-size: small;
margin-top: 0.5em;
`
export const SmallTextLight = styled(SmallText)`
color: gray;
`
export const CenteredText = styled.div`
white-space: nowrap;
text-align: center;
`
export const CenteredTextBold = styled(CenteredText)`
white-space: nowrap;
text-align: center;
font-weight: bold;
color: ${((props: any): any => String(props.color) as any) as any};
`

View File

@ -62,7 +62,7 @@ export const LotOfProviders = createExample(TestedComponent, {
"storageLimitInMegabytes": 16, "storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0" "supportedProtocolVersion": "0.0"
} }
},{ }, {
"active": true, "active": true,
"syncProviderBaseUrl": "http://sync.taler:9967/", "syncProviderBaseUrl": "http://sync.taler:9967/",
"lastSuccessfulBackupTimestamp": { "lastSuccessfulBackupTimestamp": {
@ -82,7 +82,57 @@ export const LotOfProviders = createExample(TestedComponent, {
"storageLimitInMegabytes": 16, "storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0" "supportedProtocolVersion": "0.0"
} }
},{ }, {
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.Pending,
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
}, {
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.InsufficientBalance,
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
}, {
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.TermsChanged,
newTerms: {
annualFee: 'USD:2',
storageLimitInMegabytes: 8,
supportedProtocolVersion: '2',
},
oldTerms: {
annualFee: 'USD:1',
storageLimitInMegabytes: 16,
supportedProtocolVersion: '1',
},
paidUntil: {
t_ms: 'never'
}
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
}, {
"active": false, "active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/", "syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [], "paymentProposalIds": [],
@ -94,43 +144,7 @@ export const LotOfProviders = createExample(TestedComponent, {
"storageLimitInMegabytes": 16, "storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0" "supportedProtocolVersion": "0.0"
} }
},{ }, {
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.Unpaid,
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
},{
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.Unpaid,
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
},{
"active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [],
"paymentStatus": {
"type": ProviderPaymentType.Unpaid,
},
"terms": {
"annualFee": "KUDOS:0.1",
"storageLimitInMegabytes": 16,
"supportedProtocolVersion": "0.0"
}
},{
"active": false, "active": false,
"syncProviderBaseUrl": "http://sync.demo.taler.net/", "syncProviderBaseUrl": "http://sync.demo.taler.net/",
"paymentProposalIds": [], "paymentProposalIds": [],

View File

@ -16,9 +16,14 @@
import { i18n, Timestamp } from "@gnu-taler/taler-util"; import { i18n, Timestamp } from "@gnu-taler/taler-util";
import { ProviderInfo } from "@gnu-taler/taler-wallet-core"; import { ProviderInfo, ProviderPaymentStatus } from "@gnu-taler/taler-wallet-core";
import { differenceInMonths, formatDuration, intervalToDuration } from "date-fns"; import { differenceInMonths, formatDuration, intervalToDuration } from "date-fns";
import { Fragment, JSX, VNode } from "preact"; import { FunctionalComponent, Fragment, JSX, VNode, AnyComponent } from "preact";
import {
BoldLight, ButtonPrimary, ButtonSuccess, Centered,
CenteredText, CenteredTextBold, PopupBox, Row,
SmallText, SmallTextLight
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus"; import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "./popup"; import { Pages } from "./popup";
@ -31,7 +36,7 @@ export function BackupPage({ onAddProvider }: Props): VNode {
if (!status) { if (!status) {
return <div>Loading...</div> return <div>Loading...</div>
} }
return <BackupView providers={status.providers} onAddProvider={onAddProvider} onSyncAll={status.sync}/>; return <BackupView providers={status.providers} onAddProvider={onAddProvider} onSyncAll={status.sync} />;
} }
export interface ViewProps { export interface ViewProps {
@ -42,44 +47,35 @@ export interface ViewProps {
export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps): VNode { export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps): VNode {
return ( return (
<div style={{ height: 'calc(320px - 34px - 16px)', overflow: 'auto' }}> <PopupBox style={{ justifyContent: !providers.length ? 'center' : 'space-between' }}>
<div style={{ display: 'flex', flexDirection: 'column' }}> <section>
<section style={{ flex: '1 0 auto', height: 'calc(320px - 34px - 34px - 16px)', overflow: 'auto' }}> {providers.map((provider) => <BackupLayout
status={provider.paymentStatus}
{!!providers.length && <div> timestamp={provider.lastSuccessfulBackupTimestamp}
{providers.map((provider) => { id={provider.syncProviderBaseUrl}
return <BackupLayout active={provider.active}
status={provider.paymentStatus} title={provider.syncProviderBaseUrl}
timestamp={provider.lastSuccessfulBackupTimestamp} />
id={provider.syncProviderBaseUrl} )}
active={provider.active} {!providers.length && <Centered>
title={provider.syncProviderBaseUrl} <BoldLight>No backup providers configured</BoldLight>
/> <ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
})} </Centered>}
</div>} </section>
{!providers.length && <div style={{ color: 'gray', fontWeight: 'bold', marginTop: 80, textAlign: 'center' }}> {!!providers.length && <footer>
<div>No backup providers configured</div> <ButtonPrimary onClick={onSyncAll}>{
<button class="pure-button button-success" style={{ marginTop: 15 }} onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></button> providers.length > 1 ?
</div>} <i18n.Translate>Sync all backups</i18n.Translate> :
<i18n.Translate>Sync now</i18n.Translate>
</section> }</ButtonPrimary>
{!!providers.length && <footer style={{ marginTop: 'auto', display: 'flex', flexShrink: 0 }}> <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
<div style={{ width: '100%', flexDirection: 'row', justifyContent: 'flex-end', display: 'flex' }}> </footer>}
<button class="pure-button button-secondary" style={{ marginLeft: 5 }} onClick={onSyncAll}>{ </PopupBox>
providers.length > 1 ?
<i18n.Translate>Sync all backups</i18n.Translate> :
<i18n.Translate>Sync now</i18n.Translate>
}</button>
<button class="pure-button button-success" style={{ marginLeft: 5 }} onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></button>
</div>
</footer>}
</div>
</div>
) )
} }
interface TransactionLayoutProps { interface TransactionLayoutProps {
status: any; status: ProviderPaymentStatus;
timestamp?: Timestamp; timestamp?: Timestamp;
title: string; title: string;
id: string; id: string;
@ -92,55 +88,33 @@ function BackupLayout(props: TransactionLayoutProps): JSX.Element {
dateStyle: "medium", dateStyle: "medium",
timeStyle: "short", timeStyle: "short",
} as any); } as any);
return (
<div
style={{
display: "flex",
flexDirection: "row",
border: "1px solid gray",
borderRadius: "0.5em",
margin: "0.5em 0",
justifyContent: "space-between",
padding: "0.5em",
}}
>
<div
style={{ display: "flex", flexDirection: "column", color: !props.active ? "gray" : undefined }}
>
<div style={{ }}>
<a href={Pages.provider_detail.replace(':pid', encodeURIComponent(props.id))}><span>{props.title}</span></a>
</div>
{dateStr && <div style={{ fontSize: "small", marginTop: '0.5em' }}>Last synced: {dateStr}</div>}
{!dateStr && <div style={{ fontSize: "small", color: 'gray' }}>Not synced</div>} return (
<Row>
<div style={{ color: !props.active ? "grey" : undefined }}>
<a href={Pages.provider_detail.replace(':pid', encodeURIComponent(props.id))}><span>{props.title}</span></a>
{dateStr && <SmallText>Last synced: {dateStr}</SmallText>}
{!dateStr && <SmallTextLight>Not synced</SmallTextLight>}
</div> </div>
<div style={{ <div>
marginLeft: "auto", {props.status?.type === 'paid' ?
display: "flex", <ExpirationText until={props.status.paidUntil} /> :
flexDirection: "column", <div>{props.status.type}</div>
alignItems: "center", }
alignSelf: "center"
}}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{
props.status?.type === 'paid' ?
<Fragment>
<div style={{ whiteSpace: 'nowrap', textAlign: 'center' }}>
Expires in
</div>
<div style={{ whiteSpace: 'nowrap', textAlign: 'center', fontWeight: 'bold', color: colorByTimeToExpire(props.status.paidUntil) }}>
{daysUntil(props.status.paidUntil)}
</div>
</Fragment>
:
'unpaid'
}
</div>
</div> </div>
</div> </Row>
); );
} }
function ExpirationText({ until }: { until: Timestamp }) {
return <Fragment>
<CenteredText> Expires in </CenteredText>
<CenteredTextBold {...({color:colorByTimeToExpire(until)})}> {daysUntil(until)} </CenteredTextBold>
</Fragment>
}
function colorByTimeToExpire(d: Timestamp) { function colorByTimeToExpire(d: Timestamp) {
if (d.t_ms === 'never') return 'rgb(28, 184, 65)' if (d.t_ms === 'never') return 'rgb(28, 184, 65)'
const months = differenceInMonths(d.t_ms, new Date()) const months = differenceInMonths(d.t_ms, new Date())

View File

@ -15,15 +15,11 @@
*/ */
import { BackupBackupProviderTerms, i18n, Timestamp } from "@gnu-taler/taler-util"; import { i18n, Timestamp } from "@gnu-taler/taler-util";
import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core"; import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
import { ContractTermsUtil } from "@gnu-taler/taler-wallet-core/src/util/contractTerms"; import { format, formatDuration, intervalToDuration } from "date-fns";
import { formatDuration, intervalToDuration, format } from "date-fns";
import { Fragment, VNode } from "preact"; import { Fragment, VNode } from "preact";
import { useRef, useState } from "preact/hooks"; import { useProviderStatus } from "../hooks/useProviderStatus";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { useProviderStatus } from "../hooks/useProviderStatus.js";
import * as wxApi from "../wxApi";
interface Props { interface Props {
pid: string; pid: string;

View File

@ -4,6 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="/static/style/pure.css" /> <link rel="stylesheet" type="text/css" href="/static/style/pure.css" />
<link rel="stylesheet" type="text/css" href="/static/style/popup.css" /> <link rel="stylesheet" type="text/css" href="/static/style/popup.css" />
<link rel="stylesheet" type="text/css" href="/dist/styles.css" />
<link rel="icon" href="/static/img/icon.png" /> <link rel="icon" href="/static/img/icon.png" />
<script src="/dist/popupEntryPoint.js"></script> <script src="/dist/popupEntryPoint.js"></script>
</head> </head>

File diff suppressed because it is too large Load Diff