This commit is contained in:
honzapatCZ 2021-03-24 22:27:46 +01:00
commit 79aa7a4eb0
10 changed files with 652 additions and 0 deletions

72
Parts/Button.js Normal file
View File

@ -0,0 +1,72 @@
import React from 'react'
function ButtonBase(props) {
let color = "bg-secondary hover:bg-trinary"
switch (props.type) {
case "warning":
color = "bg-accent4 hover:bg-accent4-dark"
break;
case "danger":
color = "bg-red-700 hover:bg-red-800"
break;
case "accent":
color = "bg-accent hover:bg-accent-dark"
break;
case "accent2":
color = "bg-accent2 hover:bg-accent2-dark"
break;
case "accent3":
color = "bg-accent3 hover:bg-accent3-dark"
break;
case "accent5":
color = "bg-accent5 hover:bg-accent5-dark"
break;
default:
color = ""
break;
}
return (
<button {...props}
className={color + " m-2 outline-none focus:outline-none text-primary font-bold ease-linear transition-all duration-150 " + (props.className ?? "")}
type="button"
>
{props.children}
</button>
)
}
export function ButtonBig(props) {
return (
<ButtonBase {...props} className={"px-6 py-4 rounded-2xl " + (props.className ?? "")}>
{props.children}
</ButtonBase>
)
}
export default function Button(props) {
return (
<ButtonBase {...props} className={"px-4 py-2 rounded-xl " + (props.className ?? "")}>
{props.children}
</ButtonBase>
)
}
export function ButtonSmall(props) {
return (
<ButtonBase {...props} className={"px-3 py-1 rounded " + (props.className ?? "")}>
{props.children}
</ButtonBase>
)
}
export function ButtonRound(props) {
return (
<ButtonBase {...props} className={"p-2 rounded-full " + (props.className ?? "")}>
{props.children}
</ButtonBase>
)
}
export function IconButton({icon,...props}){
return(
<a {...props} className={"cursor-pointer hover:text-primary text-secondary py-1 px-3 " + (props.className ?? "")}>
<i className={"fi fi-"+icon}></i>
</a>
)
}

17
Parts/Card.js Normal file
View File

@ -0,0 +1,17 @@
import React from "react";
export default function Card(props) {
return <div {...props} className={"relative flex flex-col min-w-0 break-words bg-primary w-full shadow-xl rounded-2xl " + (props.className ?? "")}>
{props.children}
</div>;
}
export function CardHeader(props) {
return <div className="rounded-t px-6 py-4 pb-2 bg-transparent">
<div className="flex flex-wrap items-center">
<div className="relative w-full max-w-full flex-grow flex-1">
{ props.desc != null ? <h2 className="text-primary text-xl font-semibold">{props.desc}</h2> : ""}
</div>
{props.children}
</div>
</div>;
}

375
Parts/Charts.js Normal file
View File

@ -0,0 +1,375 @@
import React, { useRef, useState } from "react";
import Chart from "chart.js";
import Card, { CardHeader } from "./Card";
import { createPopper } from "@popperjs/core";
export function ChartTooltip({ tooltipData, ...props }) {
return (
<>
<p className="font-bold">{tooltipData.title}</p>
{ tooltipData.body.map((item, index) => (
<div key={item.lines} className="flex items-center justify-center">
<span className="w-3 h-3 rounded-full" style={{ backgroundColor: tooltipData.labelColors[index].borderColor }} />
<p className="px-2 text-sm">{item.before + item.lines + item.after}</p>
</div>
))
}
</>
)
}
const setOpacity = (hex, alpha) => `${hex}${Math.floor(alpha * 255).toString(16).padStart(2, 0)}`;
function generateGetBoundingClientRect(x = 0, y = 0) { return () => ({ width: 0, height: 0, top: y, right: x, bottom: y, left: x }); }
function GetPlacement(tooltipModel) {
switch (tooltipModel.xAlign) {
case "right":
return "left";
case "left":
return "right";
}
switch (tooltipModel.yAlign) {
case "top":
return "bottom";
case "bottom":
return "top";
}
}
export default function NejChart(props) {
let [tooltipData, setTooltipData] = useState(null)
let canvasRef = useRef(null);
let popperElement = useRef(null);
let tooltipPositionEl = {
getBoundingClientRect: generateGetBoundingClientRect(100, 100),
contextElement: canvasRef.current
};
React.useEffect(() => {
var ctx = canvasRef.current.getContext("2d");
let popper = createPopper(tooltipPositionEl, popperElement.current, { placement: "bottom" });
let accentCol = getComputedStyle(document.body).getPropertyValue("--accent-dark");
let accent2Col = getComputedStyle(document.body).getPropertyValue("--accent2");
let accent3Col = getComputedStyle(document.body).getPropertyValue("--accent3");
let accent4Col = getComputedStyle(document.body).getPropertyValue("--accent4");
let accent5Col = getComputedStyle(document.body).getPropertyValue("--accent5");
let accent6Col = "rgb(180,0,0)"//getComputedStyle(document.body).getPropertyValue("--accent6");
let bgTrianry = getComputedStyle(document.body).getPropertyValue("--trinary");
let primary = getComputedStyle(document.body).getPropertyValue("--primary-text");
let secondary = getComputedStyle(document.body).getPropertyValue("--secondary-text");
console.log(Chart.defaults);
Chart.defaults.global = {
...Chart.defaults.global,
maintainAspectRatio: false,
responsive: true,
defaultColor: [accentCol, accent2Col, accent3Col, accent4Col, accent5Col, accent6Col],
legend: {
...Chart.defaults.global.legend,
labels: {
...Chart.defaults.global.legend.labels,
fontColor: secondary,
usePointStyle: true
},
},
tooltips: {
...Chart.defaults.global.tooltips,
backgroundColor: bgTrianry,
enabled: false,
custom: (tooltipModel) => {
// if chart is not defined, return early
if (!canvasRef.current) {
return;
}
// hide the tooltip when chartjs determines you've hovered out
if (tooltipModel.opacity === 0) {
setTooltipData(null);
return;
}
let position = canvasRef.current.getBoundingClientRect();
let left = position.left + tooltipModel.caretX;
let top = position.top + tooltipModel.caretY;
tooltipPositionEl.getBoundingClientRect = generateGetBoundingClientRect(left, top);
popper.setOptions({ placement: GetPlacement(tooltipModel) });
setTooltipData(tooltipModel);
},
},
}
Chart.defaults.scale = {
...Chart.defaults.scale,
ticks: {
...Chart.defaults.scale.ticks,
fontColor: secondary,
},
gridLines: {
...Chart.defaults.scale.gridLines,
drawBorder: false,
color: setOpacity(primary, 0.1),
zeroLineColor: "rgba(0, 0, 0, 0)",
/*
zeroLineBorderDash: [2],
zeroLineBorderDashOffset: [2],
*/
},
}
console.log(Chart.defaults);
console.log(props.config);
let chart = new Chart(ctx, props.config);
return ()=>{
chart.destroy();
}
}, []);
return (
<>
<canvas ref={canvasRef} />
<div ref={popperElement} className={(tooltipData ? "block " : "hidden ") + " pointer-events-none text-primary bg-trinary rounded-xl px-2 py-1"}>
{tooltipData ? <ChartTooltip tooltipData={tooltipData} /> : null}
</div>
</>
);
}
export function ExLineChart() {
let accentCol = getComputedStyle(document.body).getPropertyValue("--accent");
let bgTrianry = getComputedStyle(document.body).getPropertyValue("--trinary");
let primary = getComputedStyle(document.body).getPropertyValue("--primary-text");
let secondary = getComputedStyle(document.body).getPropertyValue("--secondary-text");
var config = {
type: "line",
data: {
labels: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
],
datasets: [
{
label: new Date().getFullYear(),
backgroundColor: accentCol,
borderColor: accentCol,
data: [65, 78, 66, 44, 56, 67, 75],
fill: true,
hoverBackgroundColor: accentCol,
hoverBorderColor: accentCol,
backgroundColor: setOpacity(accentCol, 0.1),
},
{
label: new Date().getFullYear() - 1,
backgroundColor: primary,
borderColor: primary,
data: [40, 68, 86, 74, 56, 60, 87],
fill: true,
hoverBackgroundColor: primary,
hoverBorderColor: primary,
backgroundColor: setOpacity(primary, 0.1),
},
],
},
options: {
legend: {
display: false,
},
tooltips: {
mode: "index",
intersect: false,
},
scales: {
xAxes: [
{
display: true,
scaleLabel: {
display: false,
},
gridLines: {
display: false,
},
},
],
yAxes: [
{
ticks: {
stepSize: 25
},
display: true,
scaleLabel: {
display: false,
},
gridLines: {
zeroLineBorderDash: [2],
zeroLineBorderDashOffset: [2],
},
},
],
},
}
};
return (
<Card>
<CardHeader desc="Sales"></CardHeader>
<div className="p-4 flex-auto">
<NejChart config={config} />
</div>
</Card >
)
}
export function ExBarChart() {
let accentCol = getComputedStyle(document.body).getPropertyValue("--accent");
let bgTrianry = getComputedStyle(document.body).getPropertyValue("--trinary");
let primary = getComputedStyle(document.body).getPropertyValue("--primary-text");
let secondary = getComputedStyle(document.body).getPropertyValue("--secondary-text");
var config = {
type: "bar",
data: {
labels: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
],
datasets: [
{
label: new Date().getFullYear(),
backgroundColor: accentCol,
borderColor: accentCol,
data: [65, 78, 66, 44, 56, 67, 75],
fill: false,
hoverBackgroundColor: accentCol,
hoverBorderColor: accentCol,
},
{
label: new Date().getFullYear() - 1,
backgroundColor: primary,
borderColor: primary,
data: [40, 68, 86, 74, 56, 60, 87],
fill: false,
hoverBackgroundColor: primary,
hoverBorderColor: primary,
},
],
},
options:{
legend: {
display: false,
},
scales: {
xAxes: [
{
display: true,
scaleLabel: {
display: false,
},
gridLines: {
display: false,
},
},
],
yAxes: [
{
ticks: {
stepSize: 25
},
display: true,
scaleLabel: {
display: false,
},
gridLines: {
zeroLineBorderDash: [2],
zeroLineBorderDashOffset: [2],
},
},
],
},
}
};
return (
<Card>
<CardHeader desc="Sales"></CardHeader>
<div className="p-4 flex-auto">
{/* Chart */}
<div className="relative h-350-px">
<NejChart config={config} />
</div>
</div>
</Card >
)
}
export function ExPieChart() {
let accentCol = getComputedStyle(document.body).getPropertyValue("--accent-dark");
let accent2Col = getComputedStyle(document.body).getPropertyValue("--accent2");
let accent3Col = getComputedStyle(document.body).getPropertyValue("--accent3");
let accent4Col = getComputedStyle(document.body).getPropertyValue("--accent4");
let accent5Col = getComputedStyle(document.body).getPropertyValue("--accent5");
let accent6Col = "rgb(180,0,0)"//getComputedStyle(document.body).getPropertyValue("--accent6");
var config = {
type: "pie",
data: {
labels: [
"Nejcraft",
"Honzapat",
"Kubacip",
"Viktorf1",
"Regi",
"Euler",
],
datasets: [
{
label: new Date().getFullYear(),
data: [50, 10, 10, 10, 10, 10],
fill: true,
borderColor: [accentCol, accent2Col, accent3Col, accent4Col, accent5Col, accent6Col],
hoverBorderColor: [accentCol, accent2Col, accent3Col, accent4Col, accent5Col, accent6Col],
hoverBackgroundColor: [accentCol, accent2Col, accent3Col, accent4Col, accent5Col, accent6Col],
backgroundColor: [accentCol, accent2Col, accent3Col, accent4Col, accent5Col, accent6Col],
},
],
},
options: {
legend: {
labels: {
usePointStyle: true
},
onClick: null,
align: "end",
position: "bottom",
},
}
}
return (
<Card>
<CardHeader desc="Sales"></CardHeader>
<div className="p-4 flex-auto">
{/* Chart */}
<div className="relative h-350-px">
<NejChart config={config} />
</div>
</div>
</Card >
)
}

71
Parts/DropDown.js Normal file
View File

@ -0,0 +1,71 @@
import React, { useEffect } from "react";
import { createPopper } from "@popperjs/core";
export function DropDownItem(props) {
return <button
className={"text-sm text-left py-2 px-4 focus:outline-none block w-full whitespace-no-wrap bg-transparent hover:bg-secondary text-primary"}
onClick={(e) => e.preventDefault()}
>
{props.children}
</button>;
}
export default function Dropdown(props) {
// dropdown props
const [dropdownPopoverShow, setDropdownPopoverShow] = React.useState(false);
const btnDropdownRef = React.createRef();
const popoverDropdownRef = React.createRef();
const openDropdownPopover = () => {
createPopper(btnDropdownRef.current, popoverDropdownRef.current, {
placement: props.placement ?? "left-start",
});
setDropdownPopoverShow(true);
};
const closeDropdownPopover = () => {
setDropdownPopoverShow(false);
};
function handleOutsideClick(event) {
let node = popoverDropdownRef?.current;
if (node && !node?.contains(event.target)) {
closeDropdownPopover();
}
}
useEffect(() => {
if ('ontouchend' in window) {
document.addEventListener('touchend', handleOutsideClick)
} else {
document.addEventListener('click', handleOutsideClick)
}
// Specify how to clean up after this effect:
return function cleanup() {
document.removeEventListener('touchend', handleOutsideClick)
document.removeEventListener('click', handleOutsideClick)
};
});
return (
<>
<a
className="text-secondary py-1 px-3"
href="#pablo"
ref={btnDropdownRef}
onClick={(e) => {
e.preventDefault();
dropdownPopoverShow ? closeDropdownPopover() : openDropdownPopover();
}}
>
{props.button}
</a>
<div
ref={popoverDropdownRef}
className={
(dropdownPopoverShow ? "block " : "hidden ") +
"bg-trinary text-base z-50 float-left overflow-hidden text-left rounded-xl shadow-lg min-w-48"
}
>
{props.children}
</div>
</>
);
};

31
Parts/Input.js Normal file
View File

@ -0,0 +1,31 @@
import React from 'react'
function Input(props) {
return (
<div className={props.title != null ? "mb-3": ""}>
{props.title != null ? (
<label {...props.label} className={"block text-secondary text-sm font-bold mb-2 "+props.label?.className} htmlFor={props.id || props.name || props.title}>
{props.title}
</label>
) : null}
<input {...props} name={props.name || props.title} id={props.id || props.name || props.title} className={"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.className}/>
{props.children}
</div>
)
}
function TextArea(props) {
return (
<div className="mb-3">
<label {...props.label} className={"block text-secondary text-sm font-bold mb-2 "+props.label?.className} htmlFor={props.id || props.name || props.title}>
{props.title}
</label>
<textarea {...props} name={props.name || props.title} id={props.id || props.name || props.title} className={"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.className}/>
{props.children}
</div>
)
}
export default Input
export {
TextArea
}

27
Parts/Layout.js Normal file
View File

@ -0,0 +1,27 @@
import React from 'react'
export function Full(props) {
return <div {...props} className={"w-full lg:px-2 py-2 " + (props.className??"")}>
{props.children}
</div>
}
export function Half(props) {
return <div {...props} className={"w-full lg:w-6/12 lg:px-2 py-2 " + (props.className??"")}>
{props.children}
</div>
}
export function Quarter(props) {
return <div {...props} className={"w-full lg:w-6/12 xl:w-3/12 lg:px-2 py-2 " + (props.className??"")}>
{props.children}
</div>
}
export function Third(props) {
return <div {...props} className={"w-full lg:w-4/12 lg:px-2 py-2 " + (props.className??"")}>
{props.children}
</div>
}
export function TwoThird(props) {
return <div {...props} className={"w-full lg:w-8/12 lg:px-2 py-2 " + (props.className??"")}>
{props.children}
</div>
}

14
Parts/Modal.js Normal file
View File

@ -0,0 +1,14 @@
import React from 'react'
import { Third } from './Layout'
function Modal({ isOpen, onBackdropClick, ...props }) {
if (isOpen) {
return <div onClick={onBackdropClick} className="fixed flex flex-col justify-center items-center inset-0 bg-gray-800 bg-opacity-75">
<Third {...props} onClick={e=>e.stopPropagation()}>
{props.children}
</Third>
</div>
}
return null;
}
export default Modal

12
Parts/ProgressBar.js Normal file
View File

@ -0,0 +1,12 @@
import React from "react";
export function ProgressBar(props) {
return <div className="relative w-full">
<div className={"overflow-hidden h-2 text-xs flex rounded bg-red-200 " + props.className}>
<div
style={{ width: props.percent }}
className="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-red-500"
></div>
</div>
</div>;
}

19
Parts/Table.js Normal file
View File

@ -0,0 +1,19 @@
import React from "react";
export function Table(props) {
return <div className="block w-full overflow-x-auto text-secondary">
<table className="items-center w-full bg-transparent border-collapse">
{props.children}
</table>
</div>;
}
export function TablePart(props) {
return <td className={"border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4 " + props.className}>
{props.children}
</td>;
}
export function TableHeader(props) {
return <th className={"px-6 py-3 align-middle text-xs uppercase whitespace-no-wrap font-bold text-left text-secondary border-b-2 border-secondary " + props.className}>
{props.children}
</th>;
}

14
Parts/Text.js Normal file
View File

@ -0,0 +1,14 @@
import React from 'react'
function Text() {
return (
<div>
</div>
)
}
export function Divider() {
return <hr className="my-4 md:min-w-full border-secondary" />;
}
export default Text