This commit is contained in:
Sebastian 2022-10-26 14:50:50 -03:00
parent c34e71cf3d
commit b4bad2deaf
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
31 changed files with 973 additions and 1257 deletions

View File

@ -19,10 +19,10 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { ComponentChildren, h, VNode } from 'preact';
import { useLayoutEffect, useRef } from 'preact/hooks';
import { ComponentChildren, h, VNode } from "preact";
import { useLayoutEffect, useRef } from "preact/hooks";
// import { LoadingModal } from "../modal";
import { useAsync } from '../hooks/async';
import { useAsync } from "../hooks/async";
// import { Translate } from "../../i18n";
type Props = {
@ -44,20 +44,16 @@ export function AsyncButton({
const buttonRef = useRef<HTMLButtonElement>(null);
useLayoutEffect(() => {
if (grabFocus)
buttonRef.current?.focus();
if (grabFocus) buttonRef.current?.focus();
}, [grabFocus]);
// if (isSlow) {
// return <LoadingModal onCancel={cancel} />;
// }
if (isLoading)
return <button class="button">Loading...</button>;
if (isLoading) return <button class="button">Loading...</button>;
return (
<span data-tooltip={rest['data-tooltip']} style={{ marginLeft: 5 }}>
<span data-tooltip={rest["data-tooltip"]} style={{ marginLeft: 5 }}>
<button {...rest} ref={buttonRef} onClick={request} disabled={disabled}>
{children}
</button>

View File

@ -1,5 +1,5 @@
import { h, VNode } from 'preact';
import { useRef, useState } from 'preact/hooks';
import { h, VNode } from "preact";
import { useRef, useState } from "preact/hooks";
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
@ -23,12 +23,11 @@ export function FileButton(props: Props): VNode {
</button>
<input
ref={fileInputRef}
style={{ display: 'none' }}
style={{ display: "none" }}
type="file"
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return props.onChange(undefined);
if (!f || f.length != 1) return props.onChange(undefined);
console.log(f);
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
@ -39,7 +38,7 @@ export function FileButton(props: Props): VNode {
return f[0].arrayBuffer().then((b) => {
const content = new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
"",
);
return props.onChange({
content,

View File

@ -19,7 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { h, VNode } from "preact";
export interface Notification {
message: string;
@ -27,7 +27,7 @@ export interface Notification {
type: MessageType;
}
export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS';
export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";
interface Props {
notifications: Notification[];
@ -36,16 +36,16 @@ interface Props {
function messageStyle(type: MessageType): string {
switch (type) {
case 'INFO':
return 'message is-info';
case 'WARN':
return 'message is-warning';
case 'ERROR':
return 'message is-danger';
case 'SUCCESS':
return 'message is-success';
case "INFO":
return "message is-info";
case "WARN":
return "message is-warning";
case "ERROR":
return "message is-danger";
case "SUCCESS":
return "message is-success";
default:
return 'message';
return "message";
}
}

View File

@ -14,14 +14,14 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { h, VNode } from 'preact';
import { useEffect, useRef } from 'preact/hooks';
import qrcode from 'qrcode-generator';
import { h, VNode } from "preact";
import { useEffect, useRef } from "preact/hooks";
import qrcode from "qrcode-generator";
export function QR({ text }: { text: string }): VNode {
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const qr = qrcode(0, 'L');
const qr = qrcode(0, "L");
qr.addData(text);
qr.make();
if (divRef.current)
@ -33,14 +33,14 @@ export function QR({ text }: { text: string }): VNode {
return (
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'left',
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "left",
}}
>
<div
style={{ width: '50%', minWidth: 200, maxWidth: 300 }}
style={{ width: "50%", minWidth: 200, maxWidth: 300 }}
ref={divRef}
/>
</div>

View File

@ -1,7 +1,7 @@
import { format, subYears } from 'date-fns';
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { DatePicker } from '../picker/DatePicker';
import { format, subYears } from "date-fns";
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import { DatePicker } from "../picker/DatePicker";
export interface DateInputProps {
label: string;
@ -16,13 +16,11 @@ export interface DateInputProps {
export function DateInput(props: DateInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
if (props.grabFocus) inputRef.current?.focus();
}, [props.grabFocus]);
const [opened, setOpened] = useState(false);
const value = props.bind[0] || '';
const value = props.bind[0] || "";
const [dirty, setDirty] = useState(false);
const showError = dirty && props.error;
@ -43,12 +41,10 @@ export function DateInput(props: DateInputProps): VNode {
<p class="control">
<input
type="text"
class={showError ? 'input is-danger' : 'input'}
class={showError ? "input is-danger" : "input"}
value={value}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
if (e.key === "Enter" && props.onConfirm) props.onConfirm();
}}
onInput={(e) => {
const text = e.currentTarget.value;
@ -81,7 +77,7 @@ export function DateInput(props: DateInputProps): VNode {
closeFunction={() => setOpened(false)}
dateReceiver={(d) => {
setDirty(true);
const v = format(d, 'yyyy-MM-dd');
const v = format(d, "yyyy-MM-dd");
props.bind[1](v);
}}
/>

View File

@ -1,5 +1,5 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
export interface TextInputProps {
label: string;
@ -14,9 +14,7 @@ export interface TextInputProps {
export function EmailInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
if (props.grabFocus) inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
const [dirty, setDirty] = useState(false);
@ -37,18 +35,16 @@ export function EmailInput(props: TextInputProps): VNode {
required
placeholder={props.placeholder}
type="email"
class={showError ? 'input is-danger' : 'input'}
class={showError ? "input is-danger" : "input"}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
if (e.key === "Enter" && props.onConfirm) props.onConfirm();
}}
onInput={(e) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
ref={inputRef}
style={{ display: 'block' }}
style={{ display: "block" }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}

View File

@ -18,8 +18,8 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
@ -42,9 +42,7 @@ export interface FileInputProps {
export function FileInput(props: FileInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
if (props.grabFocus) inputRef.current?.focus();
}, [props.grabFocus]);
const fileInputRef = useRef<HTMLInputElement>(null);
@ -56,9 +54,7 @@ export function FileInput(props: FileInputProps): VNode {
<div class="icon is-small ">
<i class="mdi mdi-folder" />
</div>
<span>
{props.label}
</span>
<span>{props.label}</span>
</a>
{props.tooltip && (
<span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
@ -69,15 +65,14 @@ export function FileInput(props: FileInputProps): VNode {
<div class="control">
<input
ref={fileInputRef}
style={{ display: 'none' }}
style={{ display: "none" }}
type="file"
// name={String(name)}
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return props.onChange(undefined);
if (!f || f.length != 1) return props.onChange(undefined);
console.log(f)
console.log(f);
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
setSizeError(true);
return props.onChange(undefined);
@ -87,10 +82,14 @@ export function FileInput(props: FileInputProps): VNode {
const b64 = btoa(
new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
"",
),
);
return props.onChange({content: `data:${f[0].type};base64,${b64}`, name: f[0].name, type: f[0].type});
return props.onChange({
content: `data:${f[0].type};base64,${b64}`,
name: f[0].name,
type: f[0].type,
});
});
}}
/>

View File

@ -18,19 +18,17 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import emptyImage from '../../assets/empty.png';
import { TextInputProps } from './TextInput';
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import emptyImage from "../../assets/empty.png";
import { TextInputProps } from "./TextInput";
const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export function ImageInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
if (props.grabFocus) inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
@ -59,13 +57,12 @@ export function ImageInput(props: TextInputProps): VNode {
/>
<input
ref={image}
style={{ display: 'none' }}
style={{ display: "none" }}
type="file"
name={String(name)}
onChange={(e) => {
const f: FileList | null = e.currentTarget.files;
if (!f || f.length != 1)
return onChange(emptyImage);
if (!f || f.length != 1) return onChange(emptyImage);
if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
setSizeError(true);
@ -76,7 +73,7 @@ export function ImageInput(props: TextInputProps): VNode {
const b64 = btoa(
new Uint8Array(b).reduce(
(data, byte) => data + String.fromCharCode(byte),
'',
"",
),
);
return onChange(`data:${f[0].type};base64,${b64}` as any);

View File

@ -1,5 +1,5 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
export interface TextInputProps {
label: string;
@ -14,9 +14,7 @@ export interface TextInputProps {
export function PhoneNumberInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus)
inputRef.current?.focus();
if (props.grabFocus) inputRef.current?.focus();
}, [props.grabFocus]);
const value = props.bind[0];
const [dirty, setDirty] = useState(false);
@ -36,18 +34,16 @@ export function PhoneNumberInput(props: TextInputProps): VNode {
value={value}
type="tel"
placeholder={props.placeholder}
class={showError ? 'input is-danger' : 'input'}
class={showError ? "input is-danger" : "input"}
onKeyPress={(e) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm()
if (e.key === "Enter" && props.onConfirm) props.onConfirm();
}}
onInput={(e) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
ref={inputRef}
style={{ display: 'block' }}
style={{ display: "block" }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}

View File

@ -1,8 +1,8 @@
import { h, VNode } from 'preact';
import { useLayoutEffect, useRef, useState } from 'preact/hooks';
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
export interface TextInputProps {
inputType?: 'text' | 'number' | 'multiline' | 'password';
inputType?: "text" | "number" | "multiline" | "password";
label: string;
grabFocus?: boolean;
disabled?: boolean;
@ -16,13 +16,11 @@ export interface TextInputProps {
const TextInputType = function ({ inputType, grabFocus, ...rest }: any): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (grabFocus)
inputRef.current?.focus();
if (grabFocus) inputRef.current?.focus();
}, [grabFocus]);
return inputType === 'multiline' ? (
<textarea {...rest} rows={5} ref={inputRef} style={{ height: 'unset' }} />
return inputType === "multiline" ? (
<textarea {...rest} rows={5} ref={inputRef} style={{ height: "unset" }} />
) : (
<input {...rest} type={inputType} ref={inputRef} />
);
@ -49,17 +47,15 @@ export function TextInput(props: TextInputProps): VNode {
grabFocus={props.grabFocus}
disabled={props.disabled}
placeholder={props.placeholder}
class={showError ? 'input is-danger' : 'input'}
class={showError ? "input is-danger" : "input"}
onKeyPress={(e: any) => {
if (e.key === 'Enter' && props.onConfirm)
props.onConfirm();
if (e.key === "Enter" && props.onConfirm) props.onConfirm();
}}
onInput={(e: any) => {
setDirty(true);
props.bind[1]((e.target as HTMLInputElement).value);
}}
style={{ display: 'block' }}
style={{ display: "block" }}
/>
</div>
{showError && <p class="help is-danger">{props.error}</p>}

View File

@ -19,23 +19,23 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode, Fragment } from 'preact';
import { useCallback, useEffect, useState } from 'preact/hooks';
import langIcon from '../../assets/icons/languageicon.svg';
import { useTranslationContext } from '../../context/translation';
import { strings as messages } from '../../i18n/strings';
import { h, VNode, Fragment } from "preact";
import { useCallback, useEffect, useState } from "preact/hooks";
import langIcon from "../../assets/icons/languageicon.svg";
import { useTranslationContext } from "../../context/translation";
import { strings as messages } from "../../i18n/strings";
type LangsNames = {
[P in keyof typeof messages]: string;
};
const names: LangsNames = {
es: 'Español [es]',
en: 'English [en]',
fr: 'Français [fr]',
de: 'Deutsch [de]',
sv: 'Svenska [sv]',
it: 'Italiano [it]',
es: "Español [es]",
en: "English [en]",
fr: "Français [fr]",
de: "Deutsch [de]",
sv: "Svenska [sv]",
it: "Italiano [it]",
};
function getLangName(s: keyof LangsNames | string): string {
@ -47,36 +47,38 @@ function getLangName(s: keyof LangsNames | string): string {
export function LangSelectorLikePy(): VNode {
const [updatingLang, setUpdatingLang] = useState(false);
const { lang, changeLanguage } = useTranslationContext();
const [hidden, setHidden] = useState(true)
const [hidden, setHidden] = useState(true);
useEffect(() => {
function bodyKeyPress(event: KeyboardEvent) {
if (event.code === 'Escape')
setHidden(true);
if (event.code === "Escape") setHidden(true);
}
function bodyOnClick(event: Event) {
setHidden(true);
}
document.body.addEventListener('click', bodyOnClick)
document.body.addEventListener('keydown', bodyKeyPress as any)
document.body.addEventListener("click", bodyOnClick);
document.body.addEventListener("keydown", bodyKeyPress as any);
return () => {
document.body.removeEventListener('keydown', bodyKeyPress as any)
document.body.removeEventListener('click', bodyOnClick)
}
},[])
document.body.removeEventListener("keydown", bodyKeyPress as any);
document.body.removeEventListener("click", bodyOnClick);
};
}, []);
return (
<Fragment>
<button name="language" onClick={(ev) => {
setHidden(h => !h);
<button
name="language"
onClick={(ev) => {
setHidden((h) => !h);
ev.stopPropagation();
}}>
}}
>
{getLangName(lang)}
</button>
<div id="lang" class={hidden ? 'hide' : ''}>
<div id="lang" class={hidden ? "hide" : ""}>
<div style="position: relative; overflow: visible;">
<div
class="nav"
style="position: absolute; max-height: 60vh; overflow-y: scroll">
style="position: absolute; max-height: 60vh; overflow-y: scroll"
>
{Object.keys(messages)
.filter((l) => l !== lang)
.map((l) => (
@ -88,7 +90,8 @@ export function LangSelectorLikePy(): VNode {
onClick={() => {
changeLanguage(l);
setUpdatingLang(false);
}}>
}}
>
{getLangName(l)}
</a>
))}

View File

@ -19,9 +19,9 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import logo from '../../assets/logo.jpeg';
import { LangSelectorLikePy as LangSelector } from './LangSelector';
import { h, VNode } from "preact";
import logo from "../../assets/logo.jpeg";
import { LangSelectorLikePy as LangSelector } from "./LangSelector";
interface Props {
onMobileMenu: () => void;

View File

@ -19,8 +19,8 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { Translate } from '../../i18n';
import { h, VNode } from "preact";
import { Translate } from "../../i18n";
interface Props {
mobile?: boolean;
@ -28,9 +28,9 @@ interface Props {
export function Sidebar({ mobile }: Props): VNode {
// const config = useConfigContext();
const config = { version: 'none' };
const config = { version: "none" };
// FIXME: add replacement for __VERSION__ with the current version
const process = { env: { __VERSION__: '0.0.0' } };
const process = { env: { __VERSION__: "0.0.0" } };
return (
<aside class="aside is-placed-left is-expanded">

View File

@ -14,11 +14,11 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { ComponentChildren, Fragment, h, VNode } from 'preact';
import Match from 'preact-router/match';
import { useEffect, useState } from 'preact/hooks';
import { NavigationBar } from './NavigationBar';
import { Sidebar } from './SideBar';
import { ComponentChildren, Fragment, h, VNode } from "preact";
import Match from "preact-router/match";
import { useEffect, useState } from "preact/hooks";
import { NavigationBar } from "./NavigationBar";
import { Sidebar } from "./SideBar";
interface MenuProps {
title: string;
@ -47,7 +47,7 @@ export function Menu({ title }: MenuProps): VNode {
return (
<WithTitle title={titleWithSubtitle}>
<div
class={mobileOpen ? 'has-aside-mobile-expanded' : ''}
class={mobileOpen ? "has-aside-mobile-expanded" : ""}
onClick={() => setMobileOpen(false)}
>
<NavigationBar
@ -82,11 +82,11 @@ export function NotificationCard({
<div class="column is-12">
<article
class={
n.type === 'ERROR'
? 'message is-danger'
: n.type === 'WARN'
? 'message is-warning'
: 'message is-info'
n.type === "ERROR"
? "message is-danger"
: n.type === "WARN"
? "message is-warning"
: "message is-info"
}
>
<div class="message-header">
@ -132,4 +132,4 @@ export interface Notification {
}
export type ValueOrFunction<T> = T | ((p: T) => T);
export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS';
export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";

View File

@ -19,7 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, Component } from 'preact';
import { h, Component } from "preact";
interface Props {
closeFunction?: () => void;
@ -37,36 +37,36 @@ interface State {
const now = new Date();
const monthArrShortFull = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const monthArrShort = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
const dayArr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const dayArr = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const yearArr: number[] = [];
@ -83,10 +83,10 @@ export class DatePicker extends Component<Props, State> {
dayClicked(e: any) {
const element = e.target; // the actual element clicked
if (element.innerHTML === '') return false; // don't continue if <span /> empty
if (element.innerHTML === "") return false; // don't continue if <span /> empty
// get date from clicked element (gets attached when rendered)
const date = new Date(element.getAttribute('data-value'));
const date = new Date(element.getAttribute("data-value"));
// update the state
this.setState({ currentDate: date });
@ -140,7 +140,6 @@ export class DatePicker extends Component<Props, State> {
this.setState({
displayedMonth: this.state.displayedMonth - 1,
});
}
/**
@ -156,15 +155,13 @@ export class DatePicker extends Component<Props, State> {
this.setState({
displayedMonth: this.state.displayedMonth + 1,
});
}
/**
* Display the selected month (gets fired when clicking on the date string)
*/
displaySelectedMonth() {
if (this.state.selectYearMode)
this.toggleYearSelector();
if (this.state.selectYearMode) this.toggleYearSelector();
else {
if (!this.state.currentDate) return false;
this.setState({
@ -194,7 +191,7 @@ export class DatePicker extends Component<Props, State> {
this.passDateToParent(this.state.currentDate);
}
passDateToParent(date: Date) {
if (typeof this.props.dateReceiver === 'function')
if (typeof this.props.dateReceiver === "function")
this.props.dateReceiver(date);
this.closeDatePicker();
}
@ -229,22 +226,18 @@ export class DatePicker extends Component<Props, State> {
}
render() {
const {
currentDate,
displayedMonth,
displayedYear,
selectYearMode,
} = this.state;
const { currentDate, displayedMonth, displayedYear, selectYearMode } =
this.state;
return (
<div>
<div class={`datePicker ${this.props.opened && 'datePicker--opened'}`}>
<div class={`datePicker ${this.props.opened && "datePicker--opened"}`}>
<div class="datePicker--titles">
<h3
style={{
color: selectYearMode
? 'rgba(255,255,255,.87)'
: 'rgba(255,255,255,.57)',
? "rgba(255,255,255,.87)"
: "rgba(255,255,255,.57)",
}}
onClick={this.toggleYearSelector}
>
@ -253,12 +246,12 @@ export class DatePicker extends Component<Props, State> {
<h2
style={{
color: !selectYearMode
? 'rgba(255,255,255,.87)'
: 'rgba(255,255,255,.57)',
? "rgba(255,255,255,.87)"
: "rgba(255,255,255,.57)",
}}
onClick={this.displaySelectedMonth}
>
{dayArr[currentDate.getDay()]},{' '}
{dayArr[currentDate.getDay()]},{" "}
{monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
</h2>
</div>
@ -267,7 +260,7 @@ export class DatePicker extends Component<Props, State> {
<nav>
<span onClick={this.displayPrevMonth} class="icon">
<i
style={{ transform: 'rotate(180deg)' }}
style={{ transform: "rotate(180deg)" }}
class="mdi mdi-forward"
/>
</span>
@ -284,7 +277,7 @@ export class DatePicker extends Component<Props, State> {
{!selectYearMode && (
<div class="datePicker--calendar">
<div class="datePicker--dayNames">
{['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, i) => (
{["S", "M", "T", "W", "T", "F", "S"].map((day, i) => (
<span key={i}>{day}</span>
))}
</div>
@ -309,8 +302,8 @@ export class DatePicker extends Component<Props, State> {
<span
key={day.day}
class={
(day.today ? 'datePicker--today ' : '') +
(selected ? 'datePicker--selected' : '')
(day.today ? "datePicker--today " : "") +
(selected ? "datePicker--selected" : "")
}
disabled={!day.date}
data-value={day.date}
@ -328,7 +321,7 @@ export class DatePicker extends Component<Props, State> {
{(this.props.years || yearArr).map((year) => (
<span
key={year}
class={year === displayedYear ? 'selected' : ''}
class={year === displayedYear ? "selected" : ""}
onClick={this.changeDisplayedYear}
>
{year}
@ -343,7 +336,7 @@ export class DatePicker extends Component<Props, State> {
class="datePicker--background"
onClick={this.closeDatePicker}
style={{
display: this.props.opened ? 'block' : 'none',
display: this.props.opened ? "block" : "none",
}}
/>
</div>
@ -351,6 +344,4 @@ export class DatePicker extends Component<Props, State> {
}
}
for (let i = 2010; i <= now.getFullYear() + 10; i++)
yearArr.push(i);
for (let i = 2010; i <= now.getFullYear() + 10; i++) yearArr.push(i);

View File

@ -19,16 +19,16 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, FunctionalComponent } from 'preact';
import { useState } from 'preact/hooks';
import { DurationPicker as TestedComponent } from './DurationPicker';
import { h, FunctionalComponent } from "preact";
import { useState } from "preact/hooks";
import { DurationPicker as TestedComponent } from "./DurationPicker";
export default {
title: 'Components/Picker/Duration',
title: "Components/Picker/Duration",
component: TestedComponent,
argTypes: {
onCreate: { action: 'onCreate' },
goBack: { action: 'goBack' },
onCreate: { action: "onCreate" },
goBack: { action: "goBack" },
},
};

View File

@ -19,10 +19,10 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h, VNode } from 'preact';
import { useState } from 'preact/hooks';
import { useTranslator } from '../../i18n';
import '../../scss/DurationPicker.scss';
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useTranslator } from "../../i18n";
import "../../scss/DurationPicker.scss";
export interface Props {
hours?: boolean;
@ -129,9 +129,9 @@ function InputNumber({
}}
style={{
width: 50,
border: 'none',
fontSize: 'inherit',
background: 'inherit',
border: "none",
fontSize: "inherit",
background: "inherit",
}}
/>
);
@ -157,7 +157,7 @@ function DurationColumn({
<div class="rdp-cell" key={value - 2}>
{onDecrease && (
<button
style={{ width: '100%', textAlign: 'center', margin: 5 }}
style={{ width: "100%", textAlign: "center", margin: 5 }}
onClick={onDecrease}
>
<span class="icon">
@ -167,7 +167,7 @@ function DurationColumn({
)}
</div>
<div class="rdp-cell" key={value - 1}>
{value > min ? toTwoDigitString(value - 1) : ''}
{value > min ? toTwoDigitString(value - 1) : ""}
</div>
<div class="rdp-cell rdp-center" key={value}>
{onChange ? (
@ -182,13 +182,13 @@ function DurationColumn({
</div>
<div class="rdp-cell" key={value + 1}>
{value < max ? toTwoDigitString(value + 1) : ''}
{value < max ? toTwoDigitString(value + 1) : ""}
</div>
<div class="rdp-cell" key={value + 2}>
{onIncrease && (
<button
style={{ width: '100%', textAlign: 'center', margin: 5 }}
style={{ width: "100%", textAlign: "center", margin: 5 }}
onClick={onIncrease}
>
<span class="icon">
@ -204,8 +204,7 @@ function DurationColumn({
}
function toTwoDigitString(n: number) {
if (n < 10)
return `0${n}`;
if (n < 10) return `0${n}`;
return `${n}`;
}

View File

@ -19,11 +19,11 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { createContext, h, VNode } from 'preact';
import { useContext, useEffect } from 'preact/hooks';
import { useLang } from '../hooks/index.js';
import * as jedLib from 'jed';
import { strings } from '../i18n/strings.js';
import { createContext, h, VNode } from "preact";
import { useContext, useEffect } from "preact/hooks";
import { useLang } from "../hooks/index.js";
import * as jedLib from "jed";
import { strings } from "../i18n/strings.js";
interface Type {
lang: string;
@ -31,7 +31,7 @@ interface Type {
changeLanguage: (l: string) => void;
}
const initial = {
lang: 'en',
lang: "en",
handler: null,
changeLanguage: () => {
/**
@ -55,15 +55,12 @@ export const TranslationProvider = ({
children,
forceLang,
}: Props): VNode => {
const [lang, changeLanguage] = useLang(initial);
useEffect(() => {
if (forceLang)
changeLanguage(forceLang);
if (forceLang) changeLanguage(forceLang);
});
console.log('lang store', strings);
const handler = new jedLib.Jed(strings[lang] || strings['en']);
console.log("lang store", strings);
const handler = new jedLib.Jed(strings[lang] || strings["en"]);
return h(Context.Provider, {
value: { lang, handler, changeLanguage },
children,

View File

@ -1,20 +1,20 @@
declare module '*.css' {
declare module "*.css" {
const mapping: Record<string, string>;
export default mapping;
}
declare module '*.svg' {
declare module "*.svg" {
const content: any;
export default content;
}
declare module '*.jpeg' {
declare module "*.jpeg" {
const content: any;
export default content;
}
declare module '*.png' {
declare module "*.png" {
const content: any;
export default content;
}
declare module 'jed' {
declare module "jed" {
const x: any;
export = x;
}

View File

@ -18,7 +18,7 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
import { useState } from 'preact/hooks';
import { useState } from "preact/hooks";
// import { cancelPendingRequest } from "./backend";
export interface Options {
@ -51,9 +51,9 @@ export function useAsync<T>(
}, tooLong);
try {
console.log('calling async', args);
console.log("calling async", args);
const result = await fn(...args);
console.log('async back', result);
console.log("async back", result);
setData(result);
} catch (error) {
setError(error);

View File

@ -21,9 +21,9 @@
/**
* Imports
*/
import { ComponentChild, ComponentChildren, h, Fragment, VNode } from 'preact';
import { ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact";
import { useTranslationContext } from '../context/translation';
import { useTranslationContext } from "../context/translation";
export function useTranslator() {
const ctx = useTranslationContext();
@ -46,12 +46,10 @@ export function useTranslator() {
* Convert template strings to a msgid
*/
function toI18nString(stringSeq: ReadonlyArray<string>): string {
let s = '';
let s = "";
for (let i = 0; i < stringSeq.length; i++) {
s += stringSeq[i];
if (i < stringSeq.length - 1)
s += `%${i + 1}$s`;
if (i < stringSeq.length - 1) s += `%${i + 1}$s`;
}
return s;
}
@ -64,12 +62,11 @@ interface TranslateSwitchProps {
function stringifyChildren(children: ComponentChildren): string {
let n = 1;
const ss = (children instanceof Array ? children : [children]).map((c) => {
if (typeof c === 'string')
return c;
if (typeof c === "string") return c;
return `%${n++}$s`;
});
const s = ss.join('').replace(/ +/g, ' ').trim();
const s = ss.join("").replace(/ +/g, " ").trim();
return s;
}
@ -97,13 +94,9 @@ function getTranslatedChildren(
const placeholderChildren = Array<ComponentChild>();
for (let i = 0; i < childArray.length; i++) {
const x = childArray[i];
if (x === undefined)
continue;
else if (typeof x === 'string')
continue;
else
placeholderChildren.push(x);
if (x === undefined) continue;
else if (typeof x === "string") continue;
else placeholderChildren.push(x);
}
const result = Array<ComponentChild>();
for (let i = 0; i < tr.length; i++)
@ -157,18 +150,15 @@ export function TranslateSwitch({ children, target }: TranslateSwitchProps) {
if (children)
(children instanceof Array ? children : [children]).forEach(
(child: any) => {
if (child.type === TranslatePlural)
plural = child;
if (child.type === TranslateSingular)
singular = child;
if (child.type === TranslatePlural) plural = child;
if (child.type === TranslateSingular) singular = child;
},
);
if (!singular || !plural) {
console.error('translation not found');
return h('span', {}, ['translation not found']);
console.error("translation not found");
return h("span", {}, ["translation not found"]);
}
singular.props.target = target;
plural.props.target = target;

View File

@ -17,456 +17,205 @@
/*eslint quote-props: ["error", "consistent"]*/
export const strings: { [s: string]: any } = {};
strings['de'] = {
'domain': 'messages',
'locale_data': {
'messages': {
'days': [
''
],
'hours': [
''
],
'minutes': [
''
],
'seconds': [
''
],
'Clear': [
''
],
'Logout': [
''
],
'Demo Bank': [
''
],
'Go back': [
''
],
'Wire transfer': [
''
],
'Transfer money to another account of this bank:': [
''
],
'Want to try the raw payto://-format?': [
''
],
'Transfer money via the Payto system:': [
''
],
'payto address': [
''
],
'Confirm': [
''
],
'Confirm Withdrawal': [
''
],
'Waiting the bank to create the operaion...': [
''
],
'This withdrawal was aborted!': [
''
],
'Withdraw to a Taler Wallet': [
''
],
'You can use this QR code to withdraw to your mobile wallet:': [
''
],
'this link': [
''
],
'Abort': [
''
],
'Start withdrawal': [
''
],
'Withdraw Money into a Taler wallet': [
''
],
'Amount to withdraw': [
''
],
'Please login!': [
''
],
'Login': [
''
],
'Register to the euFin bank!': [
''
],
'Registration form': [
''
],
'Register': [
''
],
'Date': [
''
],
'Amount': [
''
],
'Counterpart': [
''
],
'Subject': [
''
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
''
],
'Wrong credentials given.': [
''
],
'Account information could not be retrieved.': [
''
],
'Close wire transfer': [
''
],
'Close Taler withdrawal': [
''
],
'Bank account balance:': [
''
],
'Latest transactions:': [
''
],
'Transfer money manually': [
''
],
'List of public accounts was not found.': [
''
],
'List of public accounts could not be retrieved.': [
''
],
'History of public accounts': [
''
],
'Page has a problem: logged in but backend state is lost.': [
''
],
'Welcome to the euFin bank!': [
''
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'de'
}
}
}
strings["de"] = {
domain: "messages",
locale_data: {
messages: {
days: [""],
hours: [""],
minutes: [""],
seconds: [""],
Clear: [""],
Logout: [""],
"Demo Bank": [""],
"Go back": [""],
"Wire transfer": [""],
"Transfer money to another account of this bank:": [""],
"Want to try the raw payto://-format?": [""],
"Transfer money via the Payto system:": [""],
"payto address": [""],
Confirm: [""],
"Confirm Withdrawal": [""],
"Waiting the bank to create the operaion...": [""],
"This withdrawal was aborted!": [""],
"Withdraw to a Taler Wallet": [""],
"You can use this QR code to withdraw to your mobile wallet:": [""],
"this link": [""],
Abort: [""],
"Start withdrawal": [""],
"Withdraw Money into a Taler wallet": [""],
"Amount to withdraw": [""],
"Please login!": [""],
Login: [""],
"Register to the euFin bank!": [""],
"Registration form": [""],
Register: [""],
Date: [""],
Amount: [""],
Counterpart: [""],
Subject: [""],
"Username or account label '%1$s' not found. Won't login.": [""],
"Wrong credentials given.": [""],
"Account information could not be retrieved.": [""],
"Close wire transfer": [""],
"Close Taler withdrawal": [""],
"Bank account balance:": [""],
"Latest transactions:": [""],
"Transfer money manually": [""],
"List of public accounts was not found.": [""],
"List of public accounts could not be retrieved.": [""],
"History of public accounts": [""],
"Page has a problem: logged in but backend state is lost.": [""],
"Welcome to the euFin bank!": [""],
"": {
domain: "messages",
plural_forms: "nplurals=2; plural=(n != 1);",
lang: "de",
},
},
},
};
strings['en'] = {
'domain': 'messages',
'locale_data': {
'messages': {
'days': [
'days'
strings["en"] = {
domain: "messages",
locale_data: {
messages: {
days: ["days"],
hours: ["hours"],
minutes: ["minutes"],
seconds: ["seconds"],
Clear: [""],
Logout: [""],
"Demo Bank": [""],
"Go back": ["Go back"],
"Wire transfer": [""],
"Transfer money to another account of this bank:": [""],
"Want to try the raw payto://-format?": [""],
"Transfer money via the Payto system:": [""],
"payto address": [""],
Confirm: [""],
"Confirm Withdrawal": ["Confirm withdrawal"],
"Waiting the bank to create the operaion...": [""],
"This withdrawal was aborted!": [""],
"Withdraw to a Taler Wallet": ["Charge Taler wallet"],
"You can use this QR code to withdraw to your mobile wallet:": [""],
"this link": [""],
Abort: [""],
"Start withdrawal": ["Start withdrawal"],
"Withdraw Money into a Taler wallet": ["Charge Taler wallet"],
"Amount to withdraw": ["Amount to withdraw"],
"Please login!": [""],
Login: [""],
"Register to the euFin bank!": [""],
"Registration form": [""],
Register: [""],
Date: [""],
Amount: [""],
Counterpart: [""],
Subject: [""],
"Username or account label '%1$s' not found. Won't login.": [""],
"Wrong credentials given.": [""],
"Account information could not be retrieved.": [""],
"Close wire transfer": [""],
"Close Taler withdrawal": ["Close Taler withdrawal"],
"Bank account balance:": [""],
"Latest transactions:": [""],
"Transfer money manually": [""],
"List of public accounts was not found.": [""],
"List of public accounts could not be retrieved.": [""],
"History of public accounts": [""],
"Page has a problem: logged in but backend state is lost.": [
"Page has a problem: logged in but backend state is lost.",
],
'hours': [
'hours'
"Welcome to the euFin bank!": [
"Welcome to euFin bank: Taler+IBAN now possible!",
],
'minutes': [
'minutes'
],
'seconds': [
'seconds'
],
'Clear': [
''
],
'Logout': [
''
],
'Demo Bank': [
''
],
'Go back': [
'Go back'
],
'Wire transfer': [
''
],
'Transfer money to another account of this bank:': [
''
],
'Want to try the raw payto://-format?': [
''
],
'Transfer money via the Payto system:': [
''
],
'payto address': [
''
],
'Confirm': [
''
],
'Confirm Withdrawal': [
'Confirm withdrawal'
],
'Waiting the bank to create the operaion...': [
''
],
'This withdrawal was aborted!': [
''
],
'Withdraw to a Taler Wallet': [
'Charge Taler wallet'
],
'You can use this QR code to withdraw to your mobile wallet:': [
''
],
'this link': [
''
],
'Abort': [
''
],
'Start withdrawal': [
'Start withdrawal'
],
'Withdraw Money into a Taler wallet': [
'Charge Taler wallet'
],
'Amount to withdraw': [
'Amount to withdraw'
],
'Please login!': [
''
],
'Login': [
''
],
'Register to the euFin bank!': [
''
],
'Registration form': [
''
],
'Register': [
''
],
'Date': [
''
],
'Amount': [
''
],
'Counterpart': [
''
],
'Subject': [
''
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
''
],
'Wrong credentials given.': [
''
],
'Account information could not be retrieved.': [
''
],
'Close wire transfer': [
''
],
'Close Taler withdrawal': [
'Close Taler withdrawal'
],
'Bank account balance:': [
''
],
'Latest transactions:': [
''
],
'Transfer money manually': [
''
],
'List of public accounts was not found.': [
''
],
'List of public accounts could not be retrieved.': [
''
],
'History of public accounts': [
''
],
'Page has a problem: logged in but backend state is lost.': [
'Page has a problem: logged in but backend state is lost.'
],
'Welcome to the euFin bank!': [
'Welcome to euFin bank: Taler+IBAN now possible!'
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'en'
}
}
}
"": {
domain: "messages",
plural_forms: "nplurals=2; plural=(n != 1);",
lang: "en",
},
},
},
};
strings['it'] = {
'domain': 'messages',
'locale_data': {
'messages': {
'days': [
''
strings["it"] = {
domain: "messages",
locale_data: {
messages: {
days: [""],
hours: [""],
minutes: [""],
seconds: [""],
Clear: ["Cancella"],
Logout: [""],
"Demo Bank": ["Banca 'demo'"],
"Go back": ["Indietro"],
"Wire transfer": ["Bonifico"],
"Transfer money to another account of this bank:": [
"Trasferisci fondi a un altro conto di questa banca:",
],
'hours': [
''
"Want to try the raw payto://-format?": [
"Prova il trasferimento tramite il formato Payto!",
],
'minutes': [
''
"Transfer money via the Payto system:": [
"Effettua un bonifico tramite il sistema Payto:",
],
'seconds': [
''
"payto address": ["indirizzo Payto"],
Confirm: ["Conferma"],
"Confirm Withdrawal": ["Conferma il ritiro"],
"Waiting the bank to create the operaion...": [
"La banca sta creando l'operazione...",
],
'Clear': [
'Cancella'
"This withdrawal was aborted!": ["Questo ritiro è stato annullato!"],
"Withdraw to a Taler Wallet": ["Ritira contante nel portafoglio Taler"],
"You can use this QR code to withdraw to your mobile wallet:": [
"Usa questo codice QR per ritirare contante nel tuo wallet:",
],
'Logout': [
''
"this link": ["questo link"],
Abort: ["Annulla"],
"Start withdrawal": ["Ritira contante"],
"Withdraw Money into a Taler wallet": [
"Ritira contante nel portafoglio Taler",
],
'Demo Bank': [
'Banca \'demo\''
"Amount to withdraw": ["Somma da ritirare"],
"Please login!": ["Accedi!"],
Login: ["Accedi"],
"Register to the euFin bank!": ["Apri un conto in banca euFin!"],
"Registration form": ["Registrazione"],
Register: ["Registrati"],
Date: [""],
Amount: ["Somma"],
Counterpart: ["Controparte"],
Subject: ["Causale"],
"Username or account label '%1$s' not found. Won't login.": [
"L'utente '%1$s' non esiste. Login impossibile",
],
'Go back': [
'Indietro'
"Wrong credentials given.": ["Credenziali invalide."],
"Account information could not be retrieved.": [
"Impossibile ricevere le informazioni relative al conto.",
],
'Wire transfer': [
'Bonifico'
"Close wire transfer": ["Chiudi il bonifico"],
"Close Taler withdrawal": ["Chiudi il ritiro Taler"],
"Bank account balance:": ["Bilancio:"],
"Latest transactions:": ["Ultime transazioni:"],
"Transfer money manually": ["Effettua un bonifico"],
"List of public accounts was not found.": [
"Lista conti pubblici non trovata.",
],
'Transfer money to another account of this bank:': [
'Trasferisci fondi a un altro conto di questa banca:'
"List of public accounts could not be retrieved.": [
"Lista conti pubblici non pervenuta.",
],
'Want to try the raw payto://-format?': [
'Prova il trasferimento tramite il formato Payto!'
"History of public accounts": ["Storico dei conti pubblici"],
"Page has a problem: logged in but backend state is lost.": [
"Stato inconsistente: accesso utente effettuato ma stato con server perso.",
],
'Transfer money via the Payto system:': [
'Effettua un bonifico tramite il sistema Payto:'
],
'payto address': [
'indirizzo Payto'
],
'Confirm': [
'Conferma'
],
'Confirm Withdrawal': [
'Conferma il ritiro'
],
'Waiting the bank to create the operaion...': [
'La banca sta creando l\'operazione...'
],
'This withdrawal was aborted!': [
'Questo ritiro è stato annullato!'
],
'Withdraw to a Taler Wallet': [
'Ritira contante nel portafoglio Taler'
],
'You can use this QR code to withdraw to your mobile wallet:': [
'Usa questo codice QR per ritirare contante nel tuo wallet:'
],
'this link': [
'questo link'
],
'Abort': [
'Annulla'
],
'Start withdrawal': [
'Ritira contante'
],
'Withdraw Money into a Taler wallet': [
'Ritira contante nel portafoglio Taler'
],
'Amount to withdraw': [
'Somma da ritirare'
],
'Please login!': [
'Accedi!'
],
'Login': [
'Accedi'
],
'Register to the euFin bank!': [
'Apri un conto in banca euFin!'
],
'Registration form': [
'Registrazione'
],
'Register': [
'Registrati'
],
'Date': [
''
],
'Amount': [
'Somma'
],
'Counterpart': [
'Controparte'
],
'Subject': [
'Causale'
],
'Username or account label \'%1$s\' not found. Won\'t login.': [
'L\'utente \'%1$s\' non esiste. Login impossibile'
],
'Wrong credentials given.': [
'Credenziali invalide.'
],
'Account information could not be retrieved.': [
'Impossibile ricevere le informazioni relative al conto.'
],
'Close wire transfer': [
'Chiudi il bonifico'
],
'Close Taler withdrawal': [
'Chiudi il ritiro Taler'
],
'Bank account balance:': [
'Bilancio:'
],
'Latest transactions:': [
'Ultime transazioni:'
],
'Transfer money manually': [
'Effettua un bonifico'
],
'List of public accounts was not found.': [
'Lista conti pubblici non trovata.'
],
'List of public accounts could not be retrieved.': [
'Lista conti pubblici non pervenuta.'
],
'History of public accounts': [
'Storico dei conti pubblici'
],
'Page has a problem: logged in but backend state is lost.': [
'Stato inconsistente: accesso utente effettuato ma stato con server perso.'
],
'Welcome to the euFin bank!': [
'Benvenuti in banca euFin!'
],
'': {
'domain': 'messages',
'plural_forms': 'nplurals=2; plural=(n != 1);',
'lang': 'it'
}
}
}
"Welcome to the euFin bank!": ["Benvenuti in banca euFin!"],
"": {
domain: "messages",
plural_forms: "nplurals=2; plural=(n != 1);",
lang: "it",
},
},
},
};

View File

@ -16,14 +16,20 @@
@author Sebastian Javier Marchano
-->
<!DOCTYPE html>
<html lang="en" class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded">
<html
lang="en"
class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded"
>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="icon" href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" />
<link
rel="icon"
href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
/>
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
</head>

View File

@ -19,20 +19,18 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
import { h } from 'preact';
import Profile from './index';
import { h } from "preact";
import Profile from "./index";
export default {
title: 'Profile/View',
title: "Profile/View",
component: Profile,
argTypes: {
onSelect: { action: 'onSelect' },
onSelect: { action: "onSelect" },
},
};
export const Empty = (a: any) => <Profile {...a} />;
Empty.args = {
instances: []
}
instances: [],
};

View File

@ -135,9 +135,9 @@
text-align: center;
// there's probably a better way to do this, but wanted to try out CSS grid
grid-template-columns: calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(
100% / 7
) calc(100% / 7) calc(100% / 7) calc(100% / 7);
grid-template-columns:
calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(100% / 7)
calc(100% / 7) calc(100% / 7) calc(100% / 7);
span {
color: var(--secondary-text-color-dark);
@ -151,9 +151,9 @@
width: 100%;
display: grid;
text-align: center;
grid-template-columns: calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(
100% / 7
) calc(100% / 7) calc(100% / 7) calc(100% / 7);
grid-template-columns:
calc(100% / 7) calc(100% / 7) calc(100% / 7) calc(100% / 7)
calc(100% / 7) calc(100% / 7) calc(100% / 7);
span {
color: var(--primary-text-color-dark);

View File

@ -190,7 +190,6 @@ input {
}
}
.challenge-div {
display: block;
text-align: center;
@ -228,7 +227,6 @@ input {
}
}
.wire-transfer-form > .pure-form,
.payto-form > .pure-form,
.reserve-form > .pure-form {
@ -253,7 +251,6 @@ input {
}
}
html {
background: #ffffff;
color: #2a2a2a;

View File

@ -15,8 +15,8 @@
*/
@font-face {
font-family: 'Nunito';
font-family: "Nunito";
font-style: normal;
font-weight: 400;
src: url(./XRXV3I6Li01BKofINeaE.ttf) format('truetype');
src: url(./XRXV3I6Li01BKofINeaE.ttf) format("truetype");
}

View File

@ -186,7 +186,8 @@ textarea {
*/
button,
input { /* 1 */
input {
/* 1 */
overflow: visible;
}
@ -196,7 +197,8 @@ input { /* 1 */
*/
button,
select { /* 1 */
select {
/* 1 */
text-transform: none;
}
@ -529,7 +531,7 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-u-1-8,
.pure-u-3-24 {
width: 12.5000%;
width: 12.5%;
}
.pure-u-1-6,
@ -561,7 +563,7 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-u-3-8,
.pure-u-9-24 {
width: 37.5000%;
width: 37.5%;
}
.pure-u-2-5 {
@ -597,7 +599,7 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-u-5-8,
.pure-u-15-24 {
width: 62.5000%;
width: 62.5%;
}
.pure-u-2-3,
@ -629,7 +631,7 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-u-7-8,
.pure-u-21-24 {
width: 87.5000%;
width: 87.5%;
}
.pure-u-11-12,
@ -694,9 +696,9 @@ this the same font stack that Normalize.css sets for the `body`.
font-family: inherit;
font-size: 100%;
padding: 0.5em 1em;
color: rgba(0, 0, 0, 0.80);
color: rgba(0, 0, 0, 0.8);
border: none rgba(0, 0, 0, 0);
background-color: #E6E6E6;
background-color: #e6e6e6;
text-decoration: none;
border-radius: 2px;
}
@ -704,16 +706,29 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-button-hover,
.pure-button:hover,
.pure-button:focus {
background-image: -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10)));
background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10));
background-image: -webkit-gradient(
linear,
left top,
left bottom,
from(transparent),
color-stop(40%, rgba(0, 0, 0, 0.05)),
to(rgba(0, 0, 0, 0.1))
);
background-image: linear-gradient(
transparent,
rgba(0, 0, 0, 0.05) 40%,
rgba(0, 0, 0, 0.1)
);
}
.pure-button:focus {
outline: 0;
}
.pure-button-active,
.pure-button:active {
-webkit-box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset;
-webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset,
0 0 6px rgba(0, 0, 0, 0.2) inset;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset,
0 0 6px rgba(0, 0, 0, 0.2) inset;
border-color: #000;
}
@ -724,7 +739,7 @@ this the same font stack that Normalize.css sets for the `body`.
.pure-button-disabled:active {
border: none;
background-image: none;
opacity: 0.40;
opacity: 0.4;
cursor: not-allowed;
-webkit-box-shadow: none;
box-shadow: none;
@ -748,7 +763,6 @@ a.pure-button-selected {
margin: 0;
border-radius: 0;
border-right: 1px solid rgba(0, 0, 0, 0.2);
}
.pure-button-group .pure-button:first-child {
@ -811,14 +825,12 @@ since IE8 won't execute CSS that contains a CSS3 selector.
box-sizing: border-box;
}
/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */
/* May be able to remove this tweak as color inputs become more standardized across browsers. */
.pure-form input[type="color"] {
padding: 0.2em 0.5em;
}
.pure-form input[type="text"]:focus,
.pure-form input[type="password"]:focus,
.pure-form input[type="email"]:focus,
@ -836,7 +848,7 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-form select:focus,
.pure-form textarea:focus {
outline: 0;
border-color: #129FEA;
border-color: #129fea;
}
/*
@ -845,14 +857,14 @@ since IE8 won't execute CSS that contains a CSS3 selector.
*/
.pure-form input:not([type]):focus {
outline: 0;
border-color: #129FEA;
border-color: #129fea;
}
.pure-form input[type="file"]:focus,
.pure-form input[type="radio"]:focus,
.pure-form input[type="checkbox"]:focus {
outline: thin solid #129FEA;
outline: 1px auto #129FEA;
outline: thin solid #129fea;
outline: 1px auto #129fea;
}
.pure-form .pure-checkbox,
.pure-form .pure-radio {
@ -1248,7 +1260,7 @@ since IE8 won't execute CSS that contains a CSS3 selector.
overflow-y: hidden;
overflow-x: auto;
/* a little extra padding for this style to allow for scrollbars */
padding: .5em 0;
padding: 0.5em 0;
}
/* misc default styling */
@ -1257,13 +1269,13 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-menu-horizontal .pure-menu-children .pure-menu-separator {
background-color: #ccc;
height: 1px;
margin: .3em 0;
margin: 0.3em 0;
}
.pure-menu-horizontal .pure-menu-separator {
width: 1px;
height: 1.3em;
margin: 0 .3em ;
margin: 0 0.3em;
}
/* Need to reset the separator since submenu is vertical */
@ -1287,11 +1299,11 @@ since IE8 won't execute CSS that contains a CSS3 selector.
.pure-menu-link,
.pure-menu-heading {
padding: .5em 1em;
padding: 0.5em 1em;
}
.pure-menu-disabled {
opacity: .5;
opacity: 0.5;
}
.pure-menu-disabled .pure-menu-link:hover {
@ -1367,7 +1379,6 @@ striping:
border-bottom-width: 0;
}
/* HORIZONTAL BORDERED TABLES */
.pure-table-horizontal td,