Compare commits

..

1 Commits

Author SHA1 Message Date
5b7915bf49 small astro changes 2024-08-19 15:54:45 +02:00
13 changed files with 234 additions and 302 deletions

0
Form/index.js Normal file
View File

View File

@ -1,18 +0,0 @@
import { useTranslation } from "react-i18next";
import tw, { TwStyle } from "twin.macro";
import "styled-components/macro";
import { ComponentProps, forwardRef } from "react";
export const Badge = forwardRef<HTMLParagraphElement, { color: string | TwStyle, text: string | number }>(({ color, text, ...props }, ref) => {
const colors = {
yellow: tw`bg-yellow-500`,
gray: tw`bg-gray-500`,
red: tw`bg-red-700`,
};
const realColor = (typeof (color) === "string" && color in colors) ? colors[color] : color;
return (
<p ref={ref} css={[tw`px-2 py-1 inline text-primary text-xs font-semibold uppercase rounded-full `, realColor]} {...props}>{text}</p>
);
});

View File

@ -1,10 +1,9 @@
import React, { cloneElement, isValidElement, useEffect, useImperativeHandle, useRef, useState } from "react"; import React, { cloneElement, isValidElement, useEffect, useImperativeHandle, useRef, useState } from "react";
import { createPopper, Placement } from "@popperjs/core"; import { createPopper } from "@popperjs/core";
import { usePopper } from 'react-popper'; import { usePopper } from 'react-popper';
import styled from "styled-components"; import tw, { styled } from "twin.macro"
import tw from "twin.macro"
import { colors, colorsDisabled, colorsHover, textColors, textColorsHover } from "./Colors"; import { colors, colorsDisabled, colorsHover, textColors, textColorsHover } from "./Colors";
@ -17,16 +16,7 @@ const DropDownItem = styled.button(({ type }) => [
]) ])
export { DropDownItem } export { DropDownItem }
let Dropdown = React.forwardRef(({ children, dropdownCss = null, onValueChanged = null, button, buttonProps = null, popper = null, placement = null, hover = null, ...props }: { let Dropdown = React.forwardRef(({ children, dropdownCss, onValueChanged, button, buttonProps, popper, placement, hover, ...props }, ref) => {
children: React.ReactNode,
dropdownCss?: any,
onValueChanged?: (value: boolean) => void,
button?: React.ReactNode,
buttonProps?: any,
popper?: any,
placement?: Placement,
hover?: boolean,
}, ref) => {
// dropdown props // dropdown props
const [overButton, setOverButton] = React.useState(false); const [overButton, setOverButton] = React.useState(false);
const [overDropDown, setOverDropDown] = React.useState(false); const [overDropDown, setOverDropDown] = React.useState(false);
@ -95,14 +85,11 @@ let Dropdown = React.forwardRef(({ children, dropdownCss = null, onValueChanged
let childrenWithProps = React.Children.map(children, (item) => { let childrenWithProps = React.Children.map(children, (item) => {
if (!item) if (!item)
return; return;
//check that item is not only ReactNode
if (!isValidElement(item))
return;
let click = item.props?.onClick; let click = item.props?.onClick;
let close = item.props?.closeOnClick ?? true; let close = item.props?.closeOnClick ?? true;
return cloneElement(item, { key: children.indexOf ? children.indexOf(item) : 0, onClick: () => { close && closeDropdownPopover(); click && click() } });
return cloneElement(item as any, { key: Array.isArray(children) ? children.indexOf(item) : 0, onClick: () => { close && closeDropdownPopover(); click && click() } });
}); });
return ( return (
<> <>
<button <button
@ -129,7 +116,7 @@ let Dropdown = React.forwardRef(({ children, dropdownCss = null, onValueChanged
dropdownPopoverShow ? tw`block` : tw`hidden`, dropdownPopoverShow ? tw`block` : tw`hidden`,
tw`bg-trinary text-base z-50 float-left rounded-xl overflow-hidden text-left shadow-lg`, tw`bg-trinary text-base z-50 float-left rounded-xl overflow-hidden text-left shadow-lg`,
dropdownCss, dropdownCss,
(props as any).css props.css
]} ]}
> >
{childrenWithProps} {childrenWithProps}

View File

@ -1,12 +0,0 @@
import { Country } from "@services/accounting-api";
import { lazy, Suspense } from 'react';
export default function Flag({ country, ...props }: { country: Country | "EU" }) {
const FlagIcon = lazy(() => import(`country-flag-icons/react/3x2`).then(module => ({ default: module[country] })));
return (
<Suspense fallback={<div {...props}>...</div>}>
<FlagIcon {...props}/>
</Suspense>
);
}

111
Parts/Input.js Normal file
View File

@ -0,0 +1,111 @@
import React from "react";
import tw, { styled } from "twin.macro";
;
//import { useField as useFormikField, useFormikContext } from "formik";
const useFormikField = null;
const useFormikContext = ()=>{};
export function useField(props){
let getField = useFormikField;
const context = useFormikContext();
if(!context){
getField = (props)=>{
return [props, null, null];
}
}
return getField(props);
}
export default function Input({ label, title, children, ...props }) {
/*name, id*/
const [field, meta, helpers] = useField(props);
return (
<div css={[title && tw`my-1`]} >
{title && (
<label
{...label}
css={[tw`block text-secondary text-sm font-bold mb-2`, label?.css]}
>
{/*htmlFor={id ?? name ?? title}*/}
{title}
</label>
)}
{/*name={name || title} id={id || name || title}*/}
<input
{...field}
{...props}
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
/>
{children}
{meta?.touched && meta.error ? (
<div tw="text-[#c23c3c]">{meta.error}</div>
) : null}
</div>
);
}
export function TextArea({
label,
title,
children,
...props
}) {
const [field, meta, helpers] = useField(props);
return (
<div css={[title && tw`my-1`]} >
{title && (
<label
{...label}
css={[tw`block text-secondary text-sm font-bold mb-2`, label?.css]}
>
{title}
</label>
)}
<textarea
{...props}
{...field}
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
/>
{children}
{meta?.touched && meta.error ? (
<div tw="text-[#c23c3c]">{meta.error}</div>
) : null}
</div>
);
}
export function CheckBox({
label,
title,
children,
...props
}) {
const [field, meta, helpers] = useField(props);
return (
<div tw="my-1 flex text-secondary">
<input
{...props}
{...field}
type="checkbox"
tw="checked:bg-accent w-6 h-6 rounded-full bg-secondary border-secondary border-4 appearance-none cursor-pointer "
/>
{title != null ? (
<label
{...label}
css={[tw`block font-bold px-2`, label?.css]}
>
{title}
</label>
) : null}
{children}
</div>
);
}

View File

@ -1,187 +0,0 @@
import React from "react";
import tw from "twin.macro";
import { useField as useFormikField, useFormikContext, FieldHookConfig } from "formik";
import { IMaskInput, IMaskInputProps, IMaskMixinProps } from 'react-imask';
//const useFormikField = null;
//const useFormikContext = ()=>{};
export function useField<Val=any>(props) {
let getField = useFormikField<Val>;
const context = useFormikContext();
if (!context) {
getField = (propsOrFieldName: FieldHookConfig<any>) => {
return [props, null, null];
}
}
return getField(props);
}
export default function Input(
props: React.InputHTMLAttributes<HTMLInputElement> & FieldHookConfig<any> & {
label?: React.ComponentPropsWithoutRef<"label">;
title?: string;
children?: React.ReactNode;
className?: string;
}
) {
/*name, id*/
let { children, ...otherProps } = props;
const [field, meta, helpers] = useField(otherProps);
return (
<div css={[props.title && tw`my-1`, tw`relative`]} className={props.className}>
{props.title && (
<label
{...props.label}
htmlFor={props.id ?? props.name ?? props.title}
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
>
{/*htmlFor={id ?? name ?? title}*/}
{props.title}
</label>
)}
{/*name={name || title} id={id || name || title}*/}
<input
id={props.id ?? props.name ?? props.title}
{...field}
{...otherProps as any}
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
/>
{props.children}
{meta?.touched && meta.error ? (
<div tw="text-[#c23c3c]">{meta.error}</div>
) : null}
</div>
);
}
export function MaskedInput(
props: Omit<IMaskInputProps<HTMLInputElement>, "validate" | "label"> & FieldHookConfig<any> & {
definitions: { [k: string]: RegExp };
label?: React.ComponentPropsWithoutRef<"label">;
title?: string;
children?: React.ReactNode;
className?: string;
}
) {
/*name, id*/
let { children, validate, ...otherProps } = props;
const [field, meta, helpers] = useField({ ...otherProps, validate });
return (
<div css={[props.title && tw`my-1`, tw`relative`]} className={props.className}>
{props.title && (
<label
{...props.label}
//htmlFor={props.id ?? props.name ?? props.title}
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
>
{/*htmlFor={id ?? name ?? title}*/}
{props.title}
</label>
)}
{/*name={name || title} id={id || name || title}*/}
<IMaskInput
//id={props.id ?? props.name ?? props.title}
{...otherProps as any}
value={field.value}
unmask="typed"
onAccept={
(value, mask) => field.onChange({ target: { value, name: field.name } })
}
onBlur={field.onBlur}
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
/>
{props.children}
{meta?.touched && meta.error ? (
<div tw="text-[#c23c3c]">{meta.error}</div>
) : null}
</div>
);
}
export function TextArea({
title,
children = null,
label = null,
...props
}) {
const [field, meta, helpers] = useField(props);
return (
<div css={[title && tw`my-1`]} >
{title && (
<label
{...label}
css={[tw`block text-secondary text-sm font-bold mb-2`, label?.css]}
>
{title}
</label>
)}
<textarea
{...props}
{...field}
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
/>
{children}
{meta?.touched && meta.error ? (
<div tw="text-[#c23c3c]">{meta.error}</div>
) : null}
</div>
);
}
/**
* Renders a checkbox input with optional label and error message.
*
* @param {Object} props - The properties for the CheckBox component.
* @param {string} props.label - The label for the checkbox.
* @param {string} props.title - The title for the checkbox.
* @param {string} props.className - The class name for the container div.
* @param {ReactNode} props.children - The children components.
* @param {Object} props... - Additional properties for the checkbox input.
* @return {ReactElement} The rendered CheckBox component.
*/
export function CheckBox(
props: (Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "checked"> | Omit<FieldHookConfig<boolean>, "value">) & {
label?: React.ComponentPropsWithoutRef<"label">;
title?: string;
children?: React.ReactNode;
className?: string;
value?: boolean
}
) {
/*name, id*/
const { children, ...otherProps } = props;
const [field, meta, helpers] = useField<boolean>(otherProps);
return (
<div tw="my-1 flex text-secondary">
<input
id={props.id ?? props.name ?? props.title}
checked={otherProps?.value == undefined ? field.value : otherProps?.value}
{...field}
{...otherProps as any}
type="checkbox"
tw="checked:bg-accent w-6 h-6 rounded-full bg-secondary border-secondary border-4 appearance-none cursor-pointer "
/>
{props.title && (
<label
{...props.label}
htmlFor={props.id ?? props.name ?? props.title}
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
>
{/*htmlFor={id ?? name ?? title}*/}
{props.title}
</label>
)}
{children}
</div>
);
}

View File

@ -1,21 +0,0 @@
import React from "react"
import tw, {styled} from "twin.macro"
const Full = styled.div(tw`w-full lg:px-2 py-2`)
export {Full}
const Half = styled.div(tw`w-full lg:w-8/12 xl:w-6/12 lg:px-2 py-2`)
export {Half}
const Quarter = styled.div(tw`w-full lg:w-6/12 xl:w-3/12 lg:px-2 py-2 `)
export {Quarter}
const Sixth = styled.div(tw`w-full lg:w-1/5 xl:w-1/6 lg:px-2 py-2 `)
export {Sixth}
const Third = styled.div(tw`w-full lg:w-8/12 xl:w-4/12 lg:px-2 py-2 `)
export {Third}
const TwoThird = styled.div(tw`w-full lg:w-8/12 lg:px-2 py-2 `)
export {TwoThird}

11
Parts/Layout.jsx Normal file
View File

@ -0,0 +1,11 @@
export function Full({ className, ...props }) { return <div className={"w-full lg:px-2 py-2" + className} {...props} /> }
export function Half({ className, ...props }) { return <div className={"w-full lg:w-8/12 xl:w-6/12 lg:px-2 py-2" + className} {...props} /> }
export function Quarter({ className, ...props }) { return <div className={"w-full lg:w-6/12 xl:w-3/12 lg:px-2 py-2" + className} {...props} />; }
export function Sixth({ className, ...props }) { return <div className={"w-full lg:w-1/5 xl:w-1/6 lg:px-2 py-2" + className} {...props} />; }
export function Third({ className, ...props }) { return <div className={"w-full lg:w-8/12 xl:w-4/12 lg:px-2 py-2" + className} {...props} />; }
export function classNameoThird({ className, ...props }) { return <div className={"w-full lg:w-8/12 lg:px-2 py-2" + className} {...props} />; }

View File

@ -1,5 +1,6 @@
import Button from "./Button"; import Button from "./Button";
import tw, { styled } from "twin.macro"; import tw, { styled } from "twin.macro";
;
const Btn = styled(Button)(({ active }) => [tw`rounded-none mx-0`, active && tw`bg-accent`]); const Btn = styled(Button)(({ active }) => [tw`rounded-none mx-0`, active && tw`bg-accent`]);

View File

@ -1,37 +0,0 @@
import { MaskedInput } from "./Input";
export type PreMaskedProps = Omit<React.ComponentPropsWithoutRef<typeof MaskedInput>, "mask" | "definitions">
export function IbanInput(props: PreMaskedProps) {
return <MaskedInput {...props}
mask="XXXX XXXX XXXX XXXX [XXXX] [XXXX] [XXXX] [XX]"
definitions={{ 'X': /[0-9A-Z]/ }}
prepare={(str: string) => str.toUpperCase()}
validate={(iban: string) => {
console.log(iban);
if (iban.length < 15 || iban.length > 34)
return "Invalid length";
// Rearranged IBAN
const rearranged = iban.slice(4) + iban.slice(0, 4);
// Convert letters to numbers (A=10 ... Z=35)
const converted = rearranged.replace(/[A-Z]/g, ch => (ch.charCodeAt(0) - 55).toString());
// Perform mod-97 check
let remainder = converted;
let block;
while (remainder.length > 2) {
block = remainder.slice(0, 9);
remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(block.length);
}
if (parseInt(remainder, 10) % 97 !== 1)
return "Invalid checksum";
return null;
}}
/>
}

View File

@ -4,25 +4,22 @@ import tw, {styled} from "twin.macro"
export function Table(props) { export function Table(props) {
return <div tw="block w-full overflow-x-auto text-secondary"> return <div tw="block w-full overflow-x-auto text-secondary">
<table tw="items-center w-full bg-transparent border-collapse "> <table tw="items-center w-full bg-transparent border-collapse">
{props.children} {props.children}
</table> </table>
</div>; </div>;
} }
const TablePart = styled.td(tw`border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs p-4`) const TablePart = styled.td(tw`border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4`)
export {TablePart} export {TablePart}
const TableRow = styled.tr(tw`odd:bg-black/10 hover:bg-black/15`) const TableHeader = styled.th(tw`px-6 py-3 align-middle text-xs uppercase whitespace-nowrap font-bold text-left text-secondary border-b-2 border-secondary`)
export {TableRow}
const TableHeader = styled.th(tw`px-6 py-3 align-middle text-xs uppercase font-bold text-left text-secondary border-b-2 border-secondary`)
export {TableHeader} export {TableHeader}
const TableNote = styled.p(tw`text-xs font-normal italic normal-case`) const TableNote = styled.p(tw`text-xs font-normal italic normal-case`)
export {TableNote} export {TableNote}
const TableSidePart = styled.td(tw`border-t-0 px-8 align-middle border-l-0 border-r-0 text-xs p-4 pl-6 py-3 align-middle text-xs uppercase whitespace-nowrap font-bold text-left w-1/3 text-secondary border-r-2 border-secondary`) const TableSidePart = styled.td(tw`border-t-0 px-8 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap p-4 pl-6 py-3 align-middle text-xs uppercase whitespace-nowrap font-bold text-left w-1/3 text-secondary border-r-2 border-secondary`)
export {TableSidePart} export {TableSidePart}

75
globalStyle.js Normal file
View File

@ -0,0 +1,75 @@
import { createGlobalStyle } from "styled-components"
import tw, { theme, GlobalStyles as BaseStyles } from "twin.macro"
const CustomStyles = createGlobalStyle`
body {
-webkit-tap-highlight-color: ${theme`colors.accent`};
}
:root{
--primary: #3d3d3d;
--secondary: #535353;
--trinary: #2c2c2c;
--primary-text: #ffffff;
--secondary-text: #a0a0a0;
--primary-invert: #f3f3f3;
--secondary-invert: #dbdbdb;
--trinary-invert: #ffffff;
--primary-invert-text: #3d3d3d;
--secondary-invert-text: #535353;
--accent: #00C800;
--accent-dark: #008f00;
--accent-light: #00ed00;
--accent2: #3080FF;
--accent2-dark: #225ab4;
--accent3: #804000;
--accent3-dark: #472400;
--accent4: #F8B02C;
--accent4-dark: #bd8724;
--accent5: #9E3086;
--accent5-dark: #6b215b;
}
.light\-theme{
--primary: #f3f3f3;
--secondary: #dbdbdb;
--trinary: #ffffff;
--primary-text: #3d3d3d;
--secondary-text: #535353;
--primary-invert: #3d3d3d;
--secondary-invert: #535353;
--trinary-invert: #2c2c2c;
--primary-text-invert: #ffffff;
--secondary-text-invert: #a0a0a0;
}
::-webkit-scrollbar {
width: 0.5rem;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--secondary);
border-radius: 0.25rem;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent-dark);
}
`
const GlobalStyles = () => {
return <>
<BaseStyles />
<CustomStyles />
</>
}
export default GlobalStyles

25
styledRegistry.js Normal file
View File

@ -0,0 +1,25 @@
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({ children }) {
// Only create stylesheet once with lazy initial state
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})
if (typeof window !== 'undefined') return <>{children}</>
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}