mirror of
https://github.com/fergalmoran/xtreamium.git
synced 2026-01-03 15:35:40 +00:00
Remove windmill
This commit is contained in:
@@ -3,31 +3,36 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.5.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"@windmill/react-ui": "^0.6.0",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"classnames": "^2.3.1",
|
||||
"hls.js": "^1.1.5",
|
||||
"postcss": "^8.4.12",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-focus-lock": "^2.8.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-router-dom": "6",
|
||||
"react-scripts": "5.0.0",
|
||||
"react-toastify": "^8.2.0",
|
||||
"react-transition-group": "^4.4.2",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "^4.4.2",
|
||||
"web-vitals": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/hls.js": "^1.0.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/react": "^17.0.20",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-helmet": "^6.1.5"
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@types/react-transition-group": "^4.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
import React from "react";
|
||||
import { VscDebug } from "react-icons/vsc";
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Input,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
} from "@windmill/react-ui";
|
||||
import { BsFillMoonStarsFill, BsFillSunFill, BsSearch } from "react-icons/bs";
|
||||
import { BiLogOutCircle, BiCog } from "react-icons/bi";
|
||||
import { IoMdPerson } from "react-icons/io";
|
||||
import { AiOutlineMenu, AiOutlineBell } from "react-icons/ai";
|
||||
import { SidebarContext, ThemeContext } from "../context";
|
||||
import {
|
||||
BellIcon,
|
||||
MenuIcon,
|
||||
MoonIcon,
|
||||
OutlineCogIcon,
|
||||
OutlineLogoutIcon,
|
||||
OutlinePersonIcon,
|
||||
SearchIcon,
|
||||
SunIcon,
|
||||
} from "../icons";
|
||||
|
||||
import { toast } from "react-toastify";
|
||||
import { Avatar, Badge, Input, Dropdown, DropdownItem } from "./widgets";
|
||||
|
||||
const Header = () => {
|
||||
const { toggleSidebar } = React.useContext(SidebarContext);
|
||||
@@ -53,15 +42,14 @@ const Header = () => {
|
||||
onClick={toggleSidebar}
|
||||
aria-label="Menu"
|
||||
>
|
||||
<MenuIcon className="w-6 h-6" aria-hidden="true" />
|
||||
<AiOutlineMenu className="w-6 h-6" aria-hidden="true" />
|
||||
</button>
|
||||
<div className="flex justify-center flex-1 lg:mr-32">
|
||||
<div className="relative w-full max-w-xl mr-6 focus-within:text-purple-500">
|
||||
<div className="absolute inset-y-0 flex items-center pl-2">
|
||||
<SearchIcon className="w-4 h-4" aria-hidden="true" />
|
||||
<BsSearch className="w-4 h-4" aria-hidden="true" />
|
||||
</div>
|
||||
<Input
|
||||
css=""
|
||||
className="h-8 pl-8 text-gray-700"
|
||||
placeholder="Search for channels"
|
||||
aria-label="Search"
|
||||
@@ -85,9 +73,9 @@ const Header = () => {
|
||||
aria-label="Toggle color mode"
|
||||
>
|
||||
{theme === "dark" ? (
|
||||
<SunIcon className="w-5 h-5" aria-hidden="true" />
|
||||
<BsFillSunFill className="w-5 h-5" aria-hidden="true" />
|
||||
) : (
|
||||
<MoonIcon className="w-5 h-5" aria-hidden="true" />
|
||||
<BsFillMoonStarsFill className="w-5 h-5" aria-hidden="true" />
|
||||
)}
|
||||
</button>
|
||||
</li>
|
||||
@@ -99,7 +87,7 @@ const Header = () => {
|
||||
aria-label="Notifications"
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<BellIcon className="w-5 h-5" aria-hidden="true" />
|
||||
<AiOutlineBell className="w-5 h-5" aria-hidden="true" />
|
||||
{/* <!-- Notification badge --> */}
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@@ -146,21 +134,15 @@ const Header = () => {
|
||||
onClose={() => setIsProfileMenuOpen(false)}
|
||||
>
|
||||
<DropdownItem tag="a" href="#">
|
||||
<OutlinePersonIcon
|
||||
className="w-4 h-4 mr-3"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IoMdPerson className="w-4 h-4 mr-3" aria-hidden="true" />
|
||||
<span>Profile</span>
|
||||
</DropdownItem>
|
||||
<DropdownItem tag="a" href="#">
|
||||
<OutlineCogIcon className="w-4 h-4 mr-3" aria-hidden="true" />
|
||||
<BiCog className="w-4 h-4 mr-3" aria-hidden="true" />
|
||||
<span>Settings</span>
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={() => alert("Log out!")}>
|
||||
<OutlineLogoutIcon
|
||||
className="w-4 h-4 mr-3"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<BiLogOutCircle className="w-4 h-4 mr-3" aria-hidden="true" />
|
||||
<span>Log out</span>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
43
frontend/src/components/widgets/avatar.component.tsx
Normal file
43
frontend/src/components/widgets/avatar.component.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../constants";
|
||||
|
||||
export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
size?: "large" | "regular" | "small";
|
||||
alt?: string;
|
||||
src: string;
|
||||
}
|
||||
|
||||
const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(function Avatar(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const { size = "regular", src, alt, className, ...other } = props;
|
||||
const { avatar } = defaultTheme;
|
||||
|
||||
const baseStyle = avatar.base;
|
||||
const sizeStyles = {
|
||||
large: avatar.size.large,
|
||||
regular: avatar.size.regular,
|
||||
small: avatar.size.small,
|
||||
};
|
||||
|
||||
const cls = classNames(baseStyle, sizeStyles[size], className);
|
||||
|
||||
return (
|
||||
<div className={cls} ref={ref} {...other}>
|
||||
<img
|
||||
className="object-cover w-full h-full rounded-full"
|
||||
src={src}
|
||||
alt={alt}
|
||||
loading="lazy"
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0 rounded-full shadow-inner"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Avatar;
|
||||
34
frontend/src/components/widgets/badge.component.tsx
Normal file
34
frontend/src/components/widgets/badge.component.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React, { useContext } from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../constants";
|
||||
|
||||
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
type?: "success" | "danger" | "warning" | "neutral" | "primary";
|
||||
}
|
||||
|
||||
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(function Badge(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const { className, children, type = "primary", ...other } = props;
|
||||
|
||||
const { badge } = defaultTheme;
|
||||
const baseStyle = badge.base;
|
||||
const typeStyle = {
|
||||
success: badge.success,
|
||||
danger: badge.danger,
|
||||
warning: badge.warning,
|
||||
neutral: badge.neutral,
|
||||
primary: badge.primary,
|
||||
};
|
||||
|
||||
const cls = classNames(baseStyle, typeStyle[type], className);
|
||||
|
||||
return (
|
||||
<span className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
export default Badge;
|
||||
171
frontend/src/components/widgets/button.component.tsx
Normal file
171
frontend/src/components/widgets/button.component.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import classNames from "classnames";
|
||||
import React, { ReactNode, useContext } from "react";
|
||||
import { defaultTheme } from "../../constants";
|
||||
|
||||
type IconType =
|
||||
| string
|
||||
| React.FunctionComponent<{ className: string; "aria-hidden": boolean }>
|
||||
| React.ComponentClass<{ className: string; "aria-hidden": boolean }>;
|
||||
|
||||
export interface Props {
|
||||
children?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
size?: "larger" | "large" | "regular" | "small" | "pagination";
|
||||
icon?: IconType;
|
||||
iconLeft?: IconType;
|
||||
iconRight?: IconType;
|
||||
layout?: "outline" | "link" | "primary" | "__dropdownItem";
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
export interface ButtonAsButtonProps
|
||||
extends Props,
|
||||
React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
tag?: "button";
|
||||
type?: "button" | "submit" | "reset";
|
||||
}
|
||||
|
||||
export interface ButtonAsAnchorProps
|
||||
extends Props,
|
||||
React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
tag: "a";
|
||||
}
|
||||
|
||||
export interface ButtonAsOtherProps
|
||||
extends Props,
|
||||
React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
tag: string;
|
||||
}
|
||||
|
||||
export type ButtonProps =
|
||||
| ButtonAsButtonProps
|
||||
| ButtonAsAnchorProps
|
||||
| ButtonAsOtherProps;
|
||||
|
||||
type Ref = ReactNode | HTMLElement | string;
|
||||
|
||||
const Button = React.forwardRef<Ref, ButtonProps>(function Button(props, ref) {
|
||||
const {
|
||||
tag = "button",
|
||||
type = tag === "button" ? "button" : undefined,
|
||||
disabled = false,
|
||||
size = "regular",
|
||||
layout = "primary",
|
||||
block = false,
|
||||
icon,
|
||||
iconLeft,
|
||||
iconRight,
|
||||
className,
|
||||
children,
|
||||
...other
|
||||
} = props;
|
||||
|
||||
const { button } = defaultTheme;
|
||||
function hasIcon() {
|
||||
return !!icon || !!iconLeft || !!iconRight;
|
||||
}
|
||||
|
||||
console.warn(
|
||||
hasIcon() && !other["aria-label"] && !children,
|
||||
"Button",
|
||||
'You are using an icon button, but no "aria-label" attribute was found. Add an "aria-label" attribute to work as a label for screen readers.'
|
||||
);
|
||||
|
||||
const IconLeft = iconLeft || icon;
|
||||
const IconRight = iconRight;
|
||||
|
||||
const baseStyle = button.base;
|
||||
const blockStyle = button.block;
|
||||
const sizeStyles = {
|
||||
larger: button.size.larger,
|
||||
large: button.size.large,
|
||||
regular: button.size.regular,
|
||||
small: button.size.small,
|
||||
/**
|
||||
* Only used in Pagination.
|
||||
* Not meant for general use.
|
||||
*/
|
||||
pagination: button.size.pagination,
|
||||
};
|
||||
const iconSizeStyles = {
|
||||
larger: button.size.icon.larger,
|
||||
large: button.size.icon.large,
|
||||
regular: button.size.icon.regular,
|
||||
small: button.size.icon.small,
|
||||
pagination: button.size.icon.regular,
|
||||
};
|
||||
const iconStyle: string = button.icon[size as keyof typeof button.icon];
|
||||
const layoutStyles = {
|
||||
primary: button.primary.base,
|
||||
outline: button.outline.base,
|
||||
link: button.link.base,
|
||||
};
|
||||
const activeStyles = {
|
||||
primary: button.primary.active,
|
||||
outline: button.outline.active,
|
||||
link: button.link.active,
|
||||
};
|
||||
const disabledStyles = {
|
||||
primary: button.primary.disabled,
|
||||
outline: button.outline.disabled,
|
||||
link: button.link.disabled,
|
||||
};
|
||||
|
||||
/**
|
||||
* Only used in DropdownItem.
|
||||
* Not meant for general use.
|
||||
*/
|
||||
const dropdownItemStyle = button.dropdownItem.base;
|
||||
|
||||
const buttonStyles =
|
||||
layout === "__dropdownItem"
|
||||
? classNames(dropdownItemStyle, className)
|
||||
: classNames(
|
||||
baseStyle,
|
||||
// has icon but no children
|
||||
hasIcon() && !children && iconSizeStyles[size],
|
||||
// has icon and children
|
||||
hasIcon() && children && sizeStyles[size],
|
||||
// does not have icon
|
||||
!hasIcon() && sizeStyles[size],
|
||||
layoutStyles[layout],
|
||||
disabled ? disabledStyles[layout] : activeStyles[layout],
|
||||
block ? blockStyle : null,
|
||||
className
|
||||
);
|
||||
|
||||
const iconLeftStyles = classNames(
|
||||
iconStyle,
|
||||
children ? button.icon.left : ""
|
||||
);
|
||||
const iconRightStyles = classNames(
|
||||
iconStyle,
|
||||
children ? button.icon.right : ""
|
||||
);
|
||||
|
||||
return React.createElement(
|
||||
tag,
|
||||
{
|
||||
className: buttonStyles,
|
||||
ref,
|
||||
disabled,
|
||||
type,
|
||||
...other,
|
||||
},
|
||||
IconLeft
|
||||
? React.createElement(IconLeft, {
|
||||
className: iconLeftStyles,
|
||||
"aria-hidden": true,
|
||||
})
|
||||
: null,
|
||||
children,
|
||||
IconRight
|
||||
? React.createElement(IconRight, {
|
||||
className: iconRightStyles,
|
||||
"aria-hidden": true,
|
||||
})
|
||||
: null
|
||||
);
|
||||
});
|
||||
|
||||
export default Button;
|
||||
108
frontend/src/components/widgets/dropdown.component.tsx
Normal file
108
frontend/src/components/widgets/dropdown.component.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React, { useEffect, useContext, useRef } from "react";
|
||||
import classNames from "classnames";
|
||||
import FocusLock from "react-focus-lock";
|
||||
import { defaultTheme } from "../../constants";
|
||||
import Button, { ButtonProps } from "./button.component";
|
||||
import Transition from "./transition.component";
|
||||
|
||||
export interface DropdownProps extends React.HTMLAttributes<HTMLUListElement> {
|
||||
/**
|
||||
* Function executed when the dropdown is closed
|
||||
*/
|
||||
onClose: () => void;
|
||||
/**
|
||||
* Defines if the dropdown is open
|
||||
*/
|
||||
isOpen: boolean;
|
||||
/**
|
||||
* Defines the alignement of the dropdown related to its parent
|
||||
*/
|
||||
align?: "left" | "right";
|
||||
}
|
||||
|
||||
const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
|
||||
function Dropdown(props, ref) {
|
||||
const {
|
||||
children,
|
||||
onClose,
|
||||
isOpen,
|
||||
className,
|
||||
align = "left",
|
||||
...other
|
||||
} = props;
|
||||
const { dropdown } = defaultTheme;
|
||||
const baseStyle = dropdown.base;
|
||||
const alignStyle = dropdown.align[align];
|
||||
|
||||
function handleEsc(e: KeyboardEvent) {
|
||||
if (e.key === "Esc" || e.key === "Escape") {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
const dropdownRef = useRef<HTMLUListElement>(null);
|
||||
function handleClickOutside(e: MouseEvent) {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(e.target as Node)
|
||||
) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("click", handleClickOutside, { capture: true });
|
||||
document.addEventListener("keydown", handleEsc, { capture: true });
|
||||
return () => {
|
||||
document.removeEventListener("click", handleClickOutside);
|
||||
document.removeEventListener("keydown", handleEsc);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const cls = classNames(baseStyle, alignStyle, className);
|
||||
|
||||
return (
|
||||
<Transition
|
||||
show={isOpen}
|
||||
leave="transition ease-out duration-150"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div ref={ref}>
|
||||
<FocusLock returnFocus>
|
||||
<ul
|
||||
className={cls}
|
||||
ref={dropdownRef}
|
||||
aria-label="submenu"
|
||||
{...other}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
</FocusLock>
|
||||
</div>
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
type Ref = typeof Button;
|
||||
const DropdownItem = React.forwardRef<Ref, ButtonProps>(function DropdownItem(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
// Note: className is passed to the inner Button
|
||||
const { children, ...other } = props;
|
||||
|
||||
const { dropdownItem } = defaultTheme;
|
||||
const baseStyle = dropdownItem.base;
|
||||
|
||||
return (
|
||||
<li className={baseStyle}>
|
||||
<Button layout="__dropdownItem" ref={ref} {...other}>
|
||||
{children}
|
||||
</Button>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
export { Dropdown, DropdownItem };
|
||||
7
frontend/src/components/widgets/index.ts
Normal file
7
frontend/src/components/widgets/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import Avatar from "./avatar.component";
|
||||
import Badge from "./badge.component";
|
||||
import Button from "./button.component";
|
||||
import { Dropdown, DropdownItem } from "./dropdown.component";
|
||||
import Input from "./input.component";
|
||||
|
||||
export { Avatar, Badge, Button, Input, Dropdown, DropdownItem };
|
||||
69
frontend/src/components/widgets/input.component.tsx
Normal file
69
frontend/src/components/widgets/input.component.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, { useContext } from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../constants";
|
||||
|
||||
export interface InputProps extends React.ComponentPropsWithRef<"input"> {
|
||||
valid?: boolean;
|
||||
disabled?: boolean;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const { valid, disabled, className, type = "text", ...other } = props;
|
||||
|
||||
const { input } = defaultTheme;
|
||||
const baseStyle = input.base;
|
||||
const activeStyle = input.active;
|
||||
const disabledStyle = input.disabled;
|
||||
const validStyle = input.valid;
|
||||
const invalidStyle = input.invalid;
|
||||
const radioStyle = input.radio;
|
||||
const checkStyle = input.checkbox;
|
||||
|
||||
function hasValidation(valid: boolean | undefined) {
|
||||
return valid !== undefined;
|
||||
}
|
||||
|
||||
function validationStyle(valid: boolean | undefined): string {
|
||||
if (hasValidation(valid)) {
|
||||
return valid ? validStyle : invalidStyle;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function typeStyle(type: string): string {
|
||||
switch (type) {
|
||||
case "radio":
|
||||
return radioStyle;
|
||||
case "checkbox":
|
||||
return checkStyle;
|
||||
default:
|
||||
return baseStyle;
|
||||
}
|
||||
}
|
||||
|
||||
const cls = classNames(
|
||||
typeStyle(type),
|
||||
// don't apply activeStyle if has valid or disabled
|
||||
!hasValidation(valid) && !disabled && activeStyle,
|
||||
// don't apply disabledStyle if has valid
|
||||
!hasValidation(valid) && disabled && disabledStyle,
|
||||
validationStyle(valid),
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<input
|
||||
className={cls}
|
||||
type={type}
|
||||
ref={ref}
|
||||
disabled={disabled}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default Input;
|
||||
17
frontend/src/components/widgets/table/index.ts
Normal file
17
frontend/src/components/widgets/table/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import TableBody from "./table-body.component";
|
||||
import TableCell from "./table-cell.component";
|
||||
import TableContainer from "./table-container.component";
|
||||
import TableFooter from "./table-footer.component";
|
||||
import TableHeader from "./table-header.component";
|
||||
import TableRow from "./table-row.component";
|
||||
import Table from "./table.component";
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableFooter,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../../constants";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLTableSectionElement> {}
|
||||
|
||||
const TableBody = React.forwardRef<HTMLTableSectionElement, Props>(
|
||||
function TableBody(props, ref) {
|
||||
const { className, children, ...other } = props;
|
||||
|
||||
const { tableBody } = defaultTheme;
|
||||
const baseStyle = tableBody.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<tbody className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TableBody;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import {defaultTheme} from '../../../constants';
|
||||
|
||||
interface Props extends React.TdHTMLAttributes<HTMLTableCellElement> {}
|
||||
|
||||
const TableCell = React.forwardRef<HTMLTableCellElement, Props>(
|
||||
function TableCell(props, ref) {
|
||||
const { className, children, ...other } = props;
|
||||
|
||||
const { tableCell } = defaultTheme;
|
||||
|
||||
const baseStyle = tableCell.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<td className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TableCell;
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../../constants";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLDivElement> {}
|
||||
|
||||
const TableContainer = React.forwardRef<HTMLDivElement, Props>(
|
||||
function TableContainer(props, ref) {
|
||||
const { className, children, ...other } = props;
|
||||
const { tableContainer } = defaultTheme;
|
||||
const baseStyle = tableContainer.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<div className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TableContainer;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../../constants";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLDivElement> {}
|
||||
|
||||
const TableFooter = React.forwardRef<HTMLDivElement, Props>(
|
||||
function TableFooter(props, ref) {
|
||||
const { className, children, ...other } = props;
|
||||
|
||||
const { tableFooter } = defaultTheme;
|
||||
const baseStyle = tableFooter.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<div className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TableFooter;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../../constants";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLTableSectionElement> {}
|
||||
|
||||
const TableHeader = React.forwardRef<HTMLTableSectionElement, Props>(
|
||||
function TableHeader(props, ref) {
|
||||
const { className, children, ...other } = props;
|
||||
|
||||
const { tableHeader } = defaultTheme;
|
||||
const baseStyle = tableHeader.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<thead className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TableHeader;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
import classNames from "classnames";
|
||||
import { defaultTheme } from "../../../constants";
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLTableRowElement> {}
|
||||
|
||||
const TableRow = React.forwardRef<HTMLTableRowElement, Props>(function TableRow(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const { className, children, ...other } = props;
|
||||
|
||||
const { tableRow } = defaultTheme;
|
||||
const baseStyle = tableRow.base;
|
||||
|
||||
const cls = classNames(baseStyle, className);
|
||||
|
||||
return (
|
||||
<tr className={cls} ref={ref} {...other}>
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
export default TableRow;
|
||||
20
frontend/src/components/widgets/table/table.component.tsx
Normal file
20
frontend/src/components/widgets/table/table.component.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
export interface TableProps
|
||||
extends React.TableHTMLAttributes<HTMLTableElement> {}
|
||||
|
||||
const Table = React.forwardRef<HTMLTableElement, TableProps>(function Table(
|
||||
props,
|
||||
ref
|
||||
) {
|
||||
const { children, ...other } = props;
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<table className="w-full whitespace-nowrap" ref={ref} {...other}>
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Table;
|
||||
124
frontend/src/components/widgets/transition.component.tsx
Normal file
124
frontend/src/components/widgets/transition.component.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React, { useContext, useEffect, useRef } from "react";
|
||||
import { CSSTransition as ReactCSSTransition } from "react-transition-group";
|
||||
|
||||
interface TransitionContext {
|
||||
parent: {
|
||||
appear?: string;
|
||||
show?: boolean;
|
||||
isInitialRender?: boolean;
|
||||
};
|
||||
}
|
||||
const transitionContext = React.createContext<TransitionContext>({
|
||||
parent: {},
|
||||
});
|
||||
|
||||
function useIsInitialRender() {
|
||||
const isInitialRender = useRef(true);
|
||||
useEffect(() => {
|
||||
isInitialRender.current = false;
|
||||
}, []);
|
||||
return isInitialRender.current;
|
||||
}
|
||||
|
||||
interface TransitionProps {
|
||||
children?: React.ReactNode;
|
||||
show?: boolean;
|
||||
enter?: string;
|
||||
enterFrom?: string;
|
||||
enterTo?: string;
|
||||
leave?: string;
|
||||
leaveFrom?: string;
|
||||
leaveTo?: string;
|
||||
appear?: string;
|
||||
}
|
||||
|
||||
const CSSTransition: React.FC<TransitionProps> = function CSSTransition({
|
||||
show,
|
||||
enter = "",
|
||||
enterFrom = "",
|
||||
enterTo = "",
|
||||
leave = "",
|
||||
leaveFrom = "",
|
||||
leaveTo = "",
|
||||
appear,
|
||||
children,
|
||||
}) {
|
||||
const enterClasses = enter.split(" ").filter((s) => s.length);
|
||||
const enterFromClasses = enterFrom.split(" ").filter((s) => s.length);
|
||||
const enterToClasses = enterTo.split(" ").filter((s) => s.length);
|
||||
const leaveClasses = leave.split(" ").filter((s) => s.length);
|
||||
const leaveFromClasses = leaveFrom.split(" ").filter((s) => s.length);
|
||||
const leaveToClasses = leaveTo.split(" ").filter((s) => s.length);
|
||||
|
||||
function addClasses(node: HTMLElement, classes: string[]) {
|
||||
classes.length && node.classList.add(...classes);
|
||||
}
|
||||
|
||||
function removeClasses(node: HTMLElement, classes: string[]) {
|
||||
classes.length && node.classList.remove(...classes);
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactCSSTransition
|
||||
appear={appear}
|
||||
unmountOnExit
|
||||
in={show}
|
||||
addEndListener={(node: HTMLElement, done: any) => {
|
||||
node.addEventListener("transitionend", done, false);
|
||||
}}
|
||||
onEnter={(node: HTMLElement) => {
|
||||
addClasses(node, [...enterClasses, ...enterFromClasses]);
|
||||
}}
|
||||
onEntering={(node: HTMLElement) => {
|
||||
removeClasses(node, enterFromClasses);
|
||||
addClasses(node, enterToClasses);
|
||||
}}
|
||||
onEntered={(node: HTMLElement) => {
|
||||
removeClasses(node, [...enterToClasses, ...enterClasses]);
|
||||
}}
|
||||
onExit={(node: HTMLElement) => {
|
||||
addClasses(node, [...leaveClasses, ...leaveFromClasses]);
|
||||
}}
|
||||
onExiting={(node: HTMLElement) => {
|
||||
removeClasses(node, leaveFromClasses);
|
||||
addClasses(node, leaveToClasses);
|
||||
}}
|
||||
onExited={(node: HTMLElement) => {
|
||||
removeClasses(node, [...leaveToClasses, ...leaveClasses]);
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ReactCSSTransition>
|
||||
);
|
||||
};
|
||||
|
||||
const Transition: React.FC<TransitionProps> = function Transition({
|
||||
show,
|
||||
appear,
|
||||
...rest
|
||||
}) {
|
||||
const { parent } = useContext(transitionContext);
|
||||
const isInitialRender = useIsInitialRender();
|
||||
const isChild = show === undefined;
|
||||
|
||||
if (isChild) {
|
||||
return (
|
||||
<CSSTransition appear={parent.appear} show={parent.show} {...rest} />
|
||||
);
|
||||
} else
|
||||
return (
|
||||
<transitionContext.Provider
|
||||
value={{
|
||||
parent: {
|
||||
show,
|
||||
isInitialRender,
|
||||
appear,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CSSTransition appear={appear} show={show} {...rest} />
|
||||
</transitionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Transition;
|
||||
3
frontend/src/constants/index.ts
Normal file
3
frontend/src/constants/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import defaultTheme from "./theme";
|
||||
|
||||
export { defaultTheme };
|
||||
210
frontend/src/constants/theme.ts
Normal file
210
frontend/src/constants/theme.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
const defaultTheme = {
|
||||
// Alert
|
||||
alert: {
|
||||
base: "p-4 pl-12 relative rounded-lg leading-5",
|
||||
withClose: "pr-12",
|
||||
success: "bg-green-50 text-green-900 dark:bg-green-600 dark:text-white",
|
||||
danger: "bg-red-50 text-red-900 dark:bg-red-600 dark:text-white",
|
||||
warning: "bg-yellow-50 text-yellow-900 dark:bg-yellow-600 dark:text-white",
|
||||
neutral: "bg-gray-50 text-gray-800 dark:bg-gray-700 dark:text-gray-300",
|
||||
info: "bg-blue-50 text-blue-900 dark:bg-blue-600 dark:text-white",
|
||||
icon: {
|
||||
base: "h-5 w-5",
|
||||
success: "text-green-400 dark:text-green-300",
|
||||
danger: "text-red-400 dark:text-red-300",
|
||||
warning: "text-yellow-400 dark:text-yellow-100",
|
||||
neutral: "text-gray-400 dark:text-gray-500",
|
||||
info: "text-blue-400 dark:text-blue-300",
|
||||
},
|
||||
},
|
||||
// Pagination
|
||||
pagination: {
|
||||
base: "flex flex-col justify-between text-xs sm:flex-row text-gray-600 dark:text-gray-400",
|
||||
},
|
||||
// TableFooter
|
||||
tableFooter: {
|
||||
base: "px-4 py-3 border-t dark:border-gray-700 bg-gray-50 text-gray-500 dark:text-gray-400 dark:bg-gray-800",
|
||||
},
|
||||
// TableRow
|
||||
tableRow: {
|
||||
base: "",
|
||||
},
|
||||
// TableHeader
|
||||
tableHeader: {
|
||||
base: "text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50 dark:text-gray-400 dark:bg-gray-800",
|
||||
},
|
||||
// TableContainer
|
||||
tableContainer: {
|
||||
base: "w-full overflow-hidden rounded-lg ring-1 ring-black ring-opacity-5",
|
||||
},
|
||||
// TableCell
|
||||
tableCell: {
|
||||
base: "px-4 py-3",
|
||||
},
|
||||
// TableBody
|
||||
tableBody: {
|
||||
base: "bg-white divide-y dark:divide-gray-700 dark:bg-gray-800 text-gray-700 dark:text-gray-400",
|
||||
},
|
||||
// DropdownItem
|
||||
// this is the <li> that lives inside the Dropdown <ul>
|
||||
// you're probably looking for the dropdownItem style inside button
|
||||
dropdownItem: {
|
||||
base: "mb-2 last:mb-0",
|
||||
},
|
||||
// Dropdown
|
||||
dropdown: {
|
||||
base: "absolute w-56 p-2 mt-2 text-gray-600 bg-white border border-gray-100 rounded-lg shadow-md min-w-max-content dark:text-gray-300 dark:border-gray-700 dark:bg-gray-700",
|
||||
align: {
|
||||
left: "left-0",
|
||||
right: "right-0",
|
||||
},
|
||||
},
|
||||
// Avatar
|
||||
avatar: {
|
||||
base: "relative rounded-full inline-block",
|
||||
size: {
|
||||
large: "w-10 h-10",
|
||||
regular: "w-8 h-8",
|
||||
small: "w-6 h-6",
|
||||
},
|
||||
},
|
||||
// Modal
|
||||
modal: {
|
||||
base: "w-full px-6 py-4 overflow-hidden bg-white rounded-t-lg dark:bg-gray-800 sm:rounded-lg sm:m-4 sm:max-w-xl",
|
||||
},
|
||||
// ModalBody
|
||||
modalBody: {
|
||||
base: "mb-6 text-sm text-gray-700 dark:text-gray-400",
|
||||
},
|
||||
// ModalFooter
|
||||
modalFooter: {
|
||||
base: "flex flex-col items-center justify-end px-6 py-3 -mx-6 -mb-4 space-y-4 sm:space-y-0 sm:space-x-6 sm:flex-row bg-gray-50 dark:bg-gray-800",
|
||||
},
|
||||
// ModalHeader
|
||||
modalHeader: {
|
||||
base: "mt-4 mb-2 text-lg font-semibold text-gray-700 dark:text-gray-300",
|
||||
},
|
||||
// Badge
|
||||
badge: {
|
||||
base: "inline-flex px-2 text-xs font-medium leading-5 rounded-full",
|
||||
success:
|
||||
"text-green-700 bg-green-100 dark:bg-green-700 dark:text-green-100",
|
||||
danger: "text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700",
|
||||
warning: "text-orange-700 bg-orange-100 dark:text-white dark:bg-orange-600",
|
||||
neutral: "text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700",
|
||||
primary: "text-purple-700 bg-purple-100 dark:text-white dark:bg-purple-600",
|
||||
},
|
||||
// Backdrop
|
||||
backdrop: {
|
||||
base: "fixed inset-0 z-40 flex items-end bg-black bg-opacity-50 sm:items-center sm:justify-center",
|
||||
},
|
||||
// Textarea
|
||||
textarea: {
|
||||
base: "block w-full text-sm dark:text-gray-300 rounded-md focus:outline-none",
|
||||
active:
|
||||
"focus:border-purple-400 border-gray-300 dark:border-gray-600 dark:focus:border-gray-600 dark:bg-gray-700 dark:focus:ring-gray-300 focus:ring focus:ring-purple-300",
|
||||
disabled: "cursor-not-allowed opacity-50 bg-gray-300 dark:bg-gray-800",
|
||||
valid:
|
||||
"border-green-600 dark:bg-gray-700 focus:border-green-400 dark:focus:border-green-400 focus:ring focus:ring-green-200 dark:focus:ring-green-200",
|
||||
invalid:
|
||||
"border-red-600 dark:bg-gray-700 focus:border-red-400 dark:focus:border-red-400 focus:ring focus:ring-red-200 dark:focus:ring-red-200",
|
||||
},
|
||||
// Select
|
||||
select: {
|
||||
base: "block w-full text-sm dark:text-gray-300 focus:outline-none rounded-md",
|
||||
active:
|
||||
"focus:border-purple-400 border-gray-300 dark:border-gray-600 dark:bg-gray-700 focus:ring focus:ring-purple-300 dark:focus:ring-gray-300 dark:focus:border-gray-600",
|
||||
select: "leading-5",
|
||||
disabled: "cursor-not-allowed opacity-50 bg-gray-300 dark:bg-gray-800",
|
||||
valid:
|
||||
"border-green-600 dark:bg-gray-700 focus:border-green-400 dark:focus:border-green-400 focus:ring focus:ring-green-200 dark:focus:ring-green-200",
|
||||
invalid:
|
||||
"border-red-600 dark:bg-gray-700 focus:border-red-400 dark:focus:border-red-400 focus:ring focus:ring-red-200 dark:focus:ring-red-200",
|
||||
},
|
||||
// Label
|
||||
label: {
|
||||
base: "block text-sm text-gray-700 dark:text-gray-400",
|
||||
// check and radio get this same style
|
||||
check: "inline-flex items-center",
|
||||
disabled: "opacity-50 cursor-not-allowed",
|
||||
},
|
||||
// Input
|
||||
input: {
|
||||
base: "block w-full text-sm focus:outline-none dark:text-gray-300 leading-5 rounded-md",
|
||||
active:
|
||||
"focus:border-purple-400 border-gray-300 dark:border-gray-600 focus:ring focus:ring-purple-300 dark:focus:border-gray-600 dark:focus:ring-gray-300 dark:bg-gray-700",
|
||||
disabled: "cursor-not-allowed opacity-50 bg-gray-300 dark:bg-gray-800",
|
||||
valid:
|
||||
"border-green-600 dark:bg-gray-700 focus:border-green-400 dark:focus:border-green-400 focus:ring focus:ring-green-200 dark:focus:ring-green-200",
|
||||
invalid:
|
||||
"border-red-600 dark:bg-gray-700 focus:border-red-400 dark:focus:border-red-400 focus:ring focus:ring-red-200 dark:focus:ring-red-200",
|
||||
radio:
|
||||
"text-purple-600 form-radio focus:border-purple-400 focus:outline-none focus:ring focus:ring-purple-300 focus:ring-offset-0 dark:focus:ring-gray-300",
|
||||
checkbox:
|
||||
"text-purple-600 form-checkbox focus:border-purple-400 focus:outline-none focus:ring focus:ring-purple-300 focus:ring-offset-0 rounded dark:focus:ring-gray-300",
|
||||
},
|
||||
// HelperText
|
||||
helperText: {
|
||||
base: "text-xs",
|
||||
valid: "text-green-600 dark:text-green-400",
|
||||
invalid: "text-red-600 dark:text-red-400",
|
||||
},
|
||||
// Card
|
||||
card: {
|
||||
base: "min-w-0 rounded-lg ring-1 ring-black ring-opacity-5 overflow-hidden",
|
||||
default: "bg-white dark:bg-gray-800",
|
||||
},
|
||||
cardBody: {
|
||||
base: "p-4",
|
||||
},
|
||||
// Button
|
||||
button: {
|
||||
base: "align-bottom inline-flex items-center justify-center cursor-pointer leading-5 transition-colors duration-150 font-medium focus:outline-none",
|
||||
block: "w-full",
|
||||
size: {
|
||||
larger: "px-10 py-4 rounded-lg",
|
||||
large: "px-5 py-3 rounded-lg",
|
||||
regular: "px-4 py-2 rounded-lg text-sm",
|
||||
small: "px-3 py-1 rounded-md text-sm",
|
||||
icon: {
|
||||
larger: "p-4 rounded-lg",
|
||||
large: "p-3 rounded-lg",
|
||||
regular: "p-2 rounded-lg",
|
||||
small: "p-2 rounded-md",
|
||||
},
|
||||
pagination: "px-3 py-1 rounded-md text-xs",
|
||||
},
|
||||
// styles applied to the SVG icon
|
||||
icon: {
|
||||
larger: "h-5 w-5",
|
||||
large: "h-5 w-5",
|
||||
regular: "h-5 w-5",
|
||||
small: "h-3 w-3",
|
||||
left: "mr-2 -ml-1",
|
||||
right: "ml-2 -mr-1",
|
||||
},
|
||||
primary: {
|
||||
base: "text-white bg-purple-600 border border-transparent",
|
||||
active:
|
||||
"active:bg-purple-600 hover:bg-purple-700 focus:ring focus:ring-purple-300",
|
||||
disabled: "opacity-50 cursor-not-allowed",
|
||||
},
|
||||
outline: {
|
||||
base: "text-gray-600 border-gray-300 border dark:text-gray-400 focus:outline-none",
|
||||
active:
|
||||
"active:bg-transparent hover:border-gray-500 focus:border-gray-500 active:text-gray-500 focus:ring focus:ring-gray-300",
|
||||
disabled: "opacity-50 cursor-not-allowed bg-gray-300",
|
||||
},
|
||||
link: {
|
||||
base: "text-gray-600 dark:text-gray-400 focus:outline-none border border-transparent",
|
||||
active:
|
||||
"active:bg-transparent hover:bg-gray-100 focus:ring focus:ring-gray-300 dark:hover:bg-gray-500 dark:hover:text-gray-300 dark:hover:bg-opacity-10",
|
||||
disabled: "opacity-50 cursor-not-allowed",
|
||||
},
|
||||
// this is the button that lives inside the DropdownItem
|
||||
dropdownItem: {
|
||||
base: "inline-flex items-center cursor-pointer w-full px-2 py-1 text-sm font-medium transition-colors duration-150 rounded-md hover:bg-gray-100 hover:text-gray-800 dark:hover:bg-gray-800 dark:hover:text-gray-200",
|
||||
},
|
||||
},
|
||||
};
|
||||
export default defaultTheme;
|
||||
@@ -1,18 +1,6 @@
|
||||
import {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableCell,
|
||||
TableBody,
|
||||
TableRow,
|
||||
TableContainer,
|
||||
Badge,
|
||||
Avatar,
|
||||
Button,
|
||||
} from "@windmill/react-ui";
|
||||
import React, { Suspense } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { AiOutlinePlayCircle } from "react-icons/ai";
|
||||
import { FaChromecast } from "react-icons/fa";
|
||||
import { Stream } from "../models/stream";
|
||||
import { convertEpochToSpecificTimezone } from "../utils/date-utils";
|
||||
import { EPGComponent } from "../components";
|
||||
@@ -23,6 +11,8 @@ import {
|
||||
useMedia,
|
||||
} from "../utils/chromecast";
|
||||
import { toast } from "react-toastify";
|
||||
import { Table, TableBody, TableCell, TableContainer, TableHeader, TableRow } from "../components/widgets/table";
|
||||
import { Avatar, Badge, Button } from "../components/widgets";
|
||||
|
||||
const ChannelPage = () => {
|
||||
let params = useParams();
|
||||
@@ -142,11 +132,11 @@ const ChannelPage = () => {
|
||||
<TableContainer className="mt-5 mb-8">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<tr>
|
||||
<TableRow>
|
||||
<TableCell>Channel</TableCell>
|
||||
<TableCell>Type</TableCell>
|
||||
<TableCell></TableCell>
|
||||
</tr>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{streams.map((stream: Stream) => [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import useCast from "./useCast";
|
||||
import { Button } from "@windmill/react-ui";
|
||||
import { FaChromecast } from "react-icons/fa";
|
||||
import { Button } from "../../components/widgets";
|
||||
|
||||
interface ICastButtonProps {
|
||||
streamId: number;
|
||||
|
||||
@@ -1024,7 +1024,14 @@
|
||||
core-js-pure "^3.20.2"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||
version "7.17.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2"
|
||||
integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==
|
||||
@@ -1148,6 +1155,11 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@headlessui/react@^1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.5.0.tgz#483b44ba2c8b8d4391e1d2c863898d7dd0cc0296"
|
||||
integrity sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ==
|
||||
|
||||
"@humanwhocodes/config-array@^0.9.2":
|
||||
version "0.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
|
||||
@@ -1570,13 +1582,6 @@
|
||||
"@svgr/plugin-svgo" "^5.5.0"
|
||||
loader-utils "^2.0.0"
|
||||
|
||||
"@tailwindcss/forms@^0.3.2":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.3.4.tgz#e4939dc16450eccf4fd2029770096f38cbb556d4"
|
||||
integrity sha512-vlAoBifNJUkagB+PAdW4aHMe4pKmSLroH398UPgIogBFc91D2VlHUxe4pjxQhiJl0Nfw53sHSJSQBSTQBZP3vA==
|
||||
dependencies:
|
||||
mini-svg-data-uri "^1.2.3"
|
||||
|
||||
"@testing-library/dom@^8.0.0":
|
||||
version "8.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.12.0.tgz#fef5e545533fb084175dda6509ee71d7d2f72e23"
|
||||
@@ -1685,6 +1690,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/classnames@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.3.1.tgz#3c2467aa0f1a93f1f021e3b9bcf938bd5dfdc0dd"
|
||||
integrity sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==
|
||||
dependencies:
|
||||
classnames "*"
|
||||
|
||||
"@types/connect-history-api-fallback@^1.3.5":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae"
|
||||
@@ -1875,6 +1887,13 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.4":
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
||||
integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^17.0.20":
|
||||
version "17.0.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
|
||||
@@ -2167,18 +2186,6 @@
|
||||
"@webassemblyjs/ast" "1.11.1"
|
||||
"@xtuc/long" "4.2.2"
|
||||
|
||||
"@windmill/react-ui@^0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@windmill/react-ui/-/react-ui-0.6.0.tgz#259ee5d8b08088d4b0258fdc7595760dda6b09fe"
|
||||
integrity sha512-VjvRC0YI8V/uUMWU70XL0jHzBYmRGPMlvauLjdHJ0h60cSFm2ZrcvwIVktPi9eWw9au2cXov13rkwvVmPM/Yww==
|
||||
dependencies:
|
||||
"@tailwindcss/forms" "^0.3.2"
|
||||
classnames "2.2.6"
|
||||
deepmerge "4.2.2"
|
||||
postcss "^8.2.15"
|
||||
react-focus-lock "2.4.1"
|
||||
react-transition-group "4.4.1"
|
||||
|
||||
"@xtuc/ieee754@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
||||
@@ -2898,10 +2905,10 @@ cjs-module-lexer@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
|
||||
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
|
||||
|
||||
classnames@2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||
classnames@*, classnames@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||
|
||||
clean-css@^5.2.2:
|
||||
version "5.2.4"
|
||||
@@ -3413,7 +3420,7 @@ deep-is@^0.1.3, deep-is@~0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||
|
||||
deepmerge@4.2.2, deepmerge@^4.2.2:
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
@@ -4286,10 +4293,12 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
|
||||
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
|
||||
|
||||
focus-lock@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.7.0.tgz#b2bfb0ca7beacc8710a1ff74275fe0dc60a1d88a"
|
||||
integrity sha512-LI7v2mH02R55SekHYdv9pRHR9RajVNyIJ2N5IEkWbg7FT5ZmJ9Hw4mWxHeEUcd+dJo0QmzztHvDvWcc7prVFsw==
|
||||
focus-lock@^0.10.2:
|
||||
version "0.10.2"
|
||||
resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.10.2.tgz#561c62bae8387ecba1dd8e58a6df5ec29835c644"
|
||||
integrity sha512-DSaI/UHZ/02sg1P616aIWgToQcrKKBmcCvomDZ1PZvcJFj350PnWhSJxJ76T3e5/GbtQEARIACtbrdlrF9C5kA==
|
||||
dependencies:
|
||||
tslib "^2.0.3"
|
||||
|
||||
follow-redirects@^1.0.0:
|
||||
version "1.14.9"
|
||||
@@ -5895,11 +5904,6 @@ mini-css-extract-plugin@^2.4.5:
|
||||
dependencies:
|
||||
schema-utils "^4.0.0"
|
||||
|
||||
mini-svg-data-uri@^1.2.3:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939"
|
||||
integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==
|
||||
|
||||
minimalistic-assert@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
@@ -6911,7 +6915,7 @@ postcss@^7.0.35:
|
||||
picocolors "^0.2.1"
|
||||
source-map "^0.6.1"
|
||||
|
||||
postcss@^8.2.15, postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.4, postcss@^8.4.6, postcss@^8.4.7:
|
||||
postcss@^8.3.5, postcss@^8.4.12, postcss@^8.4.4, postcss@^8.4.6, postcss@^8.4.7:
|
||||
version "8.4.12"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
|
||||
integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
|
||||
@@ -7060,7 +7064,7 @@ react-app-polyfill@^3.0.0:
|
||||
regenerator-runtime "^0.13.9"
|
||||
whatwg-fetch "^3.6.2"
|
||||
|
||||
react-clientside-effect@^1.2.2:
|
||||
react-clientside-effect@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3"
|
||||
integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA==
|
||||
@@ -7116,17 +7120,17 @@ react-fast-compare@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
|
||||
react-focus-lock@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.4.1.tgz#e842cc93da736b5c5d331799012544295cbcee4f"
|
||||
integrity sha512-c5ZP56KSpj9EAxzScTqQO7bQQNPltf/W1ZEBDqNDOV1XOIwvAyHX0O7db9ekiAtxyKgnqZjQlLppVg94fUeL9w==
|
||||
react-focus-lock@^2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.8.1.tgz#a28f06a4ef5eab7d4ef0d859512772ec1331d529"
|
||||
integrity sha512-4kb9I7JIiBm0EJ+CsIBQ+T1t5qtmwPRbFGYFQ0t2q2qIpbFbYTHDjnjJVFB7oMBtXityEOQehblJPjqSIf3Amg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
focus-lock "^0.7.0"
|
||||
focus-lock "^0.10.2"
|
||||
prop-types "^15.6.2"
|
||||
react-clientside-effect "^1.2.2"
|
||||
use-callback-ref "^1.2.1"
|
||||
use-sidecar "^1.0.1"
|
||||
react-clientside-effect "^1.2.5"
|
||||
use-callback-ref "^1.2.5"
|
||||
use-sidecar "^1.0.5"
|
||||
|
||||
react-helmet@^6.1.0:
|
||||
version "6.1.0"
|
||||
@@ -7240,10 +7244,10 @@ react-toastify@^8.2.0:
|
||||
dependencies:
|
||||
clsx "^1.1.1"
|
||||
|
||||
react-transition-group@4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
||||
integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
|
||||
react-transition-group@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
|
||||
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
dom-helpers "^5.0.1"
|
||||
@@ -8363,12 +8367,12 @@ uri-js@^4.2.2:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
use-callback-ref@^1.2.1:
|
||||
use-callback-ref@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5"
|
||||
integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==
|
||||
|
||||
use-sidecar@^1.0.1:
|
||||
use-sidecar@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b"
|
||||
integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA==
|
||||
|
||||
Reference in New Issue
Block a user