Merge branch 'develop' into feature/add-button-component
This commit is contained in:
commit
8f1b1d8c33
@ -4,7 +4,6 @@ import React, { Fragment } from "react";
|
|||||||
import _ModalTitle from "./_ModalTitle";
|
import _ModalTitle from "./_ModalTitle";
|
||||||
import _ModalFooter from "./_ModalFooter";
|
import _ModalFooter from "./_ModalFooter";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import _ModalCloseButton from "./_ModalCloseButton";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@ -57,6 +56,5 @@ function Modal ({
|
|||||||
|
|
||||||
Modal.Header = _ModalTitle;
|
Modal.Header = _ModalTitle;
|
||||||
Modal.Footer = _ModalFooter;
|
Modal.Footer = _ModalFooter;
|
||||||
Modal.CloseButton = _ModalCloseButton;
|
|
||||||
|
|
||||||
export default Modal;
|
export default Modal;
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import { ReactComponent as SVGTimesIcon } from "assets/svg/times.svg";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
onClose: VoidFunction,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function _ModalCloseButton({onClose}: Props) {
|
|
||||||
return (
|
|
||||||
<div className="absolute right-4 top-4">
|
|
||||||
<Button
|
|
||||||
htmlType="button"
|
|
||||||
iconed="only"
|
|
||||||
className="w-10 h-10"
|
|
||||||
variant="gray"
|
|
||||||
type="text"
|
|
||||||
onClick={onClose}
|
|
||||||
>
|
|
||||||
<SVGTimesIcon className="w-full h-full stroke-current" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,239 +0,0 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import {
|
|
||||||
StyleColorVariants,
|
|
||||||
StyleColorVariantsMap,
|
|
||||||
StyleType,
|
|
||||||
} from 'core/_variants';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
href?: string;
|
|
||||||
variant?: StyleColorVariants;
|
|
||||||
type?: StyleType;
|
|
||||||
iconed?: boolean | "only";
|
|
||||||
glowing?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
onClick?: (event: React.MouseEvent) => void;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
className?: string | undefined;
|
|
||||||
rel?: string | undefined;
|
|
||||||
htmlType?: 'button' | 'submit' | 'reset' | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonBgVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'bg-gray-500',
|
|
||||||
blue: 'bg-blue-500',
|
|
||||||
emerald: 'bg-emerald-600',
|
|
||||||
pink: 'bg-pink-500',
|
|
||||||
purple: 'bg-purple-500',
|
|
||||||
red: 'bg-red-500',
|
|
||||||
sky: 'bg-sky-500',
|
|
||||||
yellow: 'bg-yellow-500',
|
|
||||||
"dark-coral": "bg-dark-coral-500",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonBgDisabledVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'bg-gray-200',
|
|
||||||
blue: 'bg-blue-100/10',
|
|
||||||
emerald: 'bg-emerald-200/50',
|
|
||||||
pink: 'bg-pink-200/50',
|
|
||||||
purple: 'bg-purple-200/50',
|
|
||||||
red: 'bg-red-200/50',
|
|
||||||
sky: 'bg-sky-200/50',
|
|
||||||
yellow: 'bg-yellow-200/50',
|
|
||||||
"dark-coral": "bg-dark-coral-200/50",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonBgDisabledHoverVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'hover:bg-gray-500/50',
|
|
||||||
blue: 'hover:bg-blue-100/10',
|
|
||||||
emerald: 'hover:bg-emerald-500/50',
|
|
||||||
pink: 'hover:bg-pink-500/50',
|
|
||||||
purple: 'hover:bg-purple-500/50',
|
|
||||||
red: 'hover:bg-red-500/50',
|
|
||||||
sky: 'hover:bg-sky-500/50',
|
|
||||||
yellow: 'hover:bg-yellow-500/50',
|
|
||||||
"dark-coral": "hover:bg-dark-coral-500/50",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonHoverBgVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'hover:bg-gray-600',
|
|
||||||
blue: 'hover:bg-blue-400',
|
|
||||||
emerald: 'hover:bg-emerald-600',
|
|
||||||
pink: 'hover:bg-pink-600',
|
|
||||||
purple: 'hover:bg-purple-600',
|
|
||||||
red: 'hover:bg-red-600',
|
|
||||||
sky: 'hover:bg-sky-600',
|
|
||||||
yellow: 'hover:bg-yellow-600',
|
|
||||||
"dark-coral": "hover:bg-dark-coral-600",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonBorderVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'border-gray-500',
|
|
||||||
blue: 'border-blue-500',
|
|
||||||
emerald: 'border-emerald-700',
|
|
||||||
pink: 'border-pink-300',
|
|
||||||
purple: 'border-purple-300',
|
|
||||||
red: 'border-red-300',
|
|
||||||
sky: 'border-sky-300',
|
|
||||||
yellow: 'border-yellow-300',
|
|
||||||
"dark-coral": "border-dark-coral-500",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonBorderHoverVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'hover:border-gray-500',
|
|
||||||
blue: 'hover:border-blue-400',
|
|
||||||
emerald: 'hover:border-emerald-900',
|
|
||||||
pink: 'hover:border-pink-400',
|
|
||||||
purple: 'hover:border-purple-400',
|
|
||||||
red: 'hover:border-red-500',
|
|
||||||
sky: 'hover:border-sky-400',
|
|
||||||
yellow: 'hover:border-yellow-400',
|
|
||||||
"dark-coral": "hover:border-dark-coral-400",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonTextVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'text-white',
|
|
||||||
blue: 'text-white',
|
|
||||||
emerald: 'text-emerald-300',
|
|
||||||
pink: 'text-white',
|
|
||||||
purple: 'text-white',
|
|
||||||
red: 'text-white',
|
|
||||||
sky: 'text-white',
|
|
||||||
yellow: 'text-white',
|
|
||||||
"dark-coral": "text-white",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonTextHoverVariants: StyleColorVariantsMap<string> = {
|
|
||||||
blue: 'hover:text-white',
|
|
||||||
emerald: 'hover:text-emerald-900',
|
|
||||||
gray: 'hover:text-white',
|
|
||||||
pink: 'hover:text-white',
|
|
||||||
purple: 'hover:text-white',
|
|
||||||
red: 'hover:text-white',
|
|
||||||
sky: 'hover:text-white',
|
|
||||||
yellow: 'hover:text-white',
|
|
||||||
"dark-coral": 'hover:text-white',
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonTextMutedVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'text-gray-500',
|
|
||||||
blue: 'text-gray-50',
|
|
||||||
emerald: 'text-gray-50',
|
|
||||||
pink: 'text-gray-50',
|
|
||||||
purple: 'text-gray-50',
|
|
||||||
red: 'text-gray-50',
|
|
||||||
sky: 'text-gray-50',
|
|
||||||
yellow: 'text-gray-50',
|
|
||||||
"dark-coral": "text-gray-500",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonGlowVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'shadow-gray-300/50',
|
|
||||||
blue: 'shadow-blue-500/50',
|
|
||||||
emerald: 'shadow-blue-700/50',
|
|
||||||
pink: 'shadow-blue-300/50',
|
|
||||||
purple: 'shadow-blue-300/50',
|
|
||||||
red: 'shadow-blue-300/50',
|
|
||||||
sky: 'shadow-blue-300/50',
|
|
||||||
yellow: 'shadow-blue-300/50',
|
|
||||||
"dark-coral": "shadow-dark-coral-300/50",
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonHoverGlowVariants: StyleColorVariantsMap<string> = {
|
|
||||||
gray: 'hover:shadow-gray-300/50',
|
|
||||||
blue: 'hover:shadow-blue-400/50',
|
|
||||||
emerald: 'hover:shadow-blue-300/50',
|
|
||||||
pink: 'hover:shadow-blue-300/50',
|
|
||||||
purple: 'hover:shadow-blue-300/50',
|
|
||||||
red: 'hover:shadow-blue-300/50',
|
|
||||||
sky: 'hover:shadow-blue-300/50',
|
|
||||||
yellow: 'hover:shadow-blue-300/50',
|
|
||||||
"dark-coral": "hover:shadow-dark-coral-300/50",
|
|
||||||
};
|
|
||||||
|
|
||||||
const isURL = (str: string) =>
|
|
||||||
/^(?:\w+:)?\/\/([^\s.]+\.\S{2}|localhost[:?\d]*)\S*$/.test(str);
|
|
||||||
|
|
||||||
const isInternalURL = (str: string) => /^\/(\S*\/)*\S*\/?$/.test(str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common button component
|
|
||||||
* @param {string|undefined} href New location link
|
|
||||||
* @param {boolean} iconed Flag to process component with icon. Default: `false`
|
|
||||||
* @param {StyleGlobalVariants|undefined} variant Button variant.
|
|
||||||
* Default: `base`
|
|
||||||
* @param {StyleType} type Button type.
|
|
||||||
* Default: `fill`
|
|
||||||
* @param {boolean|undefined} glowing Enables glowing shadow around
|
|
||||||
* button element. Default `false`
|
|
||||||
* @param {boolean|undefined} disabled Shows button element as
|
|
||||||
* disabled item
|
|
||||||
* @return {JSX.Element}
|
|
||||||
*/
|
|
||||||
const Button = ({
|
|
||||||
href,
|
|
||||||
iconed,
|
|
||||||
variant = 'gray',
|
|
||||||
type = 'fill',
|
|
||||||
glowing = false,
|
|
||||||
disabled,
|
|
||||||
onClick: onPress,
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
rel,
|
|
||||||
htmlType,
|
|
||||||
}: Props) =>{
|
|
||||||
const isExternal = isURL(href ?? '');
|
|
||||||
const isInternal = isInternalURL(href ?? '');
|
|
||||||
|
|
||||||
const As = isExternal || isInternal ? 'a' : 'button';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<As
|
|
||||||
rel={rel}
|
|
||||||
href={href}
|
|
||||||
type={htmlType}
|
|
||||||
onClick={!disabled ? onPress : undefined}
|
|
||||||
className={classNames([
|
|
||||||
'text-center',
|
|
||||||
'rounded-lg font-semibold',
|
|
||||||
'transition-[box-shadow,background-color,color,border-color]',
|
|
||||||
'border',
|
|
||||||
{
|
|
||||||
'px-2 py-2': iconed === "only",
|
|
||||||
'py-3 pl-2 pr-5': iconed && iconed !== "only",
|
|
||||||
'py-3 px-8': !iconed,
|
|
||||||
'!cursor-default': disabled,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'shadow-lg': !disabled && glowing && type !== 'text',
|
|
||||||
'hover:shadow-lg': !disabled && glowing,
|
|
||||||
// Text variants
|
|
||||||
[`${buttonTextVariants[variant]}`]: !disabled,
|
|
||||||
[`${buttonTextHoverVariants[variant]}`]: !disabled && type === "outline",
|
|
||||||
// Background variants
|
|
||||||
[`${buttonBgVariants[variant]}`]: !disabled && type === 'fill',
|
|
||||||
[`${buttonHoverBgVariants[variant]}`]: !disabled,
|
|
||||||
// Glowing variants
|
|
||||||
[`${buttonGlowVariants[variant]}`]:
|
|
||||||
!disabled && glowing === true && type !== 'text',
|
|
||||||
[`${buttonHoverGlowVariants[variant]}`]: glowing,
|
|
||||||
// Disabled variants
|
|
||||||
[`${buttonTextMutedVariants[variant]}`]: disabled,
|
|
||||||
[`${buttonBgDisabledVariants[variant]}`]: disabled && type === 'fill',
|
|
||||||
[`${buttonBgDisabledHoverVariants[variant]}`]: disabled,
|
|
||||||
// Border variants
|
|
||||||
[`${buttonBorderVariants[variant]}`]: type !== 'text',
|
|
||||||
'!border-transparent': disabled || type === 'text',
|
|
||||||
},
|
|
||||||
buttonBorderHoverVariants[variant],
|
|
||||||
className,
|
|
||||||
])}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</As>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Button;
|
|
@ -1,6 +1,5 @@
|
|||||||
import { Combobox } from "@headlessui/react";
|
import { Combobox } from "@headlessui/react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { ReactComponent as SVGDropdownIcon } from "assets/svg/dropdown.svg";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
type OptionPropsArg = {
|
type OptionPropsArg = {
|
||||||
@ -50,10 +49,6 @@ export default function Combox<T = any>({
|
|||||||
/>
|
/>
|
||||||
<Combobox.Button className="absolute inset-y-0 right-0 p-2.5 flex items-center w-10 hover:bg-blue-500
|
<Combobox.Button className="absolute inset-y-0 right-0 p-2.5 flex items-center w-10 hover:bg-blue-500
|
||||||
border-l-2 border-blue-900/50 transition-colors">
|
border-l-2 border-blue-900/50 transition-colors">
|
||||||
<SVGDropdownIcon
|
|
||||||
className="w-full h-full fill-white"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</Combobox.Button>
|
</Combobox.Button>
|
||||||
</div>
|
</div>
|
||||||
<Combobox.Options
|
<Combobox.Options
|
||||||
@ -77,7 +72,7 @@ export default function Combox<T = any>({
|
|||||||
}
|
}
|
||||||
value={valueMaper ? valueMaper(option) : option}
|
value={valueMaper ? valueMaper(option) : option}
|
||||||
>
|
>
|
||||||
{(stats) => itemBuilder(stats, option)}
|
|
||||||
</Combobox.Option>
|
</Combobox.Option>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
@ -11,11 +11,9 @@ import { useTranslation } from "react-i18next";
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Components */
|
/* Components */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import Button from "components/controls/Button";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Icons */
|
/* Icons */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGBackIcon } from "assets/svg/backstab.svg";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Component */
|
/* Component */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -36,20 +34,6 @@ export default function GlobalControls() {
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Button
|
|
||||||
type="fill"
|
|
||||||
variant="blue"
|
|
||||||
onClick={() => navigate(-1)}
|
|
||||||
className="font-bold"
|
|
||||||
iconed
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<div className="flex-none w-6 h-6">
|
|
||||||
<SVGBackIcon className="w-full h-full stroke-current opacity-60"/>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">{t('back')}</div>
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</Transition>
|
</Transition>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -8,17 +8,11 @@ import { useNavigate } from "react-router-dom";
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import ContextMenu from "components/containers/contextmenu/ContextMenu";
|
import ContextMenu from "components/containers/contextmenu/ContextMenu";
|
||||||
import Logotype from "components/Logotype";
|
import Logotype from "components/Logotype";
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import Avatar from "components/containers/Avatar";
|
import Avatar from "components/containers/Avatar";
|
||||||
import ContextMenuAction from "components/containers/contextmenu/ContextMenuAction";
|
import ContextMenuAction from "components/containers/contextmenu/ContextMenuAction";
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* SVG */
|
/* SVG */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGSearchIcon } from "assets/svg/search.svg";
|
|
||||||
import { ReactComponent as SVGBellIcon } from "assets/svg/bell.svg";
|
|
||||||
import { ReactComponent as SVGCogIcon } from "assets/svg/cog.svg";
|
|
||||||
import { ReactComponent as SVGUserAddIcon } from "assets/svg/user-add.svg";
|
|
||||||
import { ReactComponent as SVGExitIcon } from "assets/svg/exit.svg";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Hooks */
|
/* Hooks */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -66,12 +60,7 @@ export default function Header({title}: Props) {
|
|||||||
<Logotype name={title} />
|
<Logotype name={title} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-none flex items-center space-x-3">
|
<div className="flex-none flex items-center space-x-3">
|
||||||
<Button iconed="only" className="w-10 h-10" variant="blue" type="text" onClick={showSearchbar}>
|
|
||||||
<SVGSearchIcon className="w-full h-full stroke-current" />
|
|
||||||
</Button>
|
|
||||||
<Button iconed="only" className="w-10 h-10" variant="blue" type="text">
|
|
||||||
<SVGBellIcon className="w-full h-full stroke-current" />
|
|
||||||
</Button>
|
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
button={<Avatar className="p-2" />}
|
button={<Avatar className="p-2" />}
|
||||||
className="absolute w-full min-h-14 sm:w-80 -bottom-3
|
className="absolute w-full min-h-14 sm:w-80 -bottom-3
|
||||||
@ -100,9 +89,7 @@ export default function Header({title}: Props) {
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md hover:text-blue-400 transition-colors"
|
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md hover:text-blue-400 transition-colors"
|
||||||
caption="Account settings"
|
caption="Account settings"
|
||||||
icon={
|
|
||||||
<SVGCogIcon className="w-6 h-6 stroke-gray-200/30 group-hover:stroke-current" />
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<ContextMenuAction
|
<ContextMenuAction
|
||||||
action={() => {
|
action={() => {
|
||||||
@ -111,17 +98,13 @@ export default function Header({title}: Props) {
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md hover:text-blue-400 transition-colors"
|
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md hover:text-blue-400 transition-colors"
|
||||||
caption={t("account.connect")}
|
caption={t("account.connect")}
|
||||||
icon={
|
|
||||||
<SVGUserAddIcon className="w-6 h-6 stroke-gray-200/30 group-hover:stroke-current" />
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<ContextMenuAction
|
<ContextMenuAction
|
||||||
action={signOut}
|
action={signOut}
|
||||||
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md transition-colors"
|
className="group w-full py-2 -mx-4 px-4 hover:bg-gray-200/20 rounded-md transition-colors"
|
||||||
caption={t('logOut')}
|
caption={t('logOut')}
|
||||||
icon={
|
|
||||||
<SVGExitIcon className="w-6 h-6 stroke-gray-200/30 group-hover:stroke-current" />
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export type StyleType = "fill" | "outline" | "text";
|
export type StyleType = "high" | "medium" | "low";
|
||||||
|
|
||||||
export type StyleColorVariants = "blue" | "pink" | "red" | "purple" | "yellow" | "sky" | "emerald" | "gray" | "dark-coral";
|
export type StyleColorVariants = "blue" | "pink" | "red" | "purple" | "yellow" | "sky" | "emerald" | "gray" | "dark-coral";
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ export default function LanguageSelector({ isShown, onClose }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
||||||
<Modal.CloseButton onClose={onClose} />
|
|
||||||
<Modal.Header>{t("selectLanguage")}</Modal.Header>
|
<Modal.Header>{t("selectLanguage")}</Modal.Header>
|
||||||
<Combox
|
<Combox
|
||||||
options={Object.keys(languages)}
|
options={Object.keys(languages)}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Libraries */
|
/* Libraries */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import StandalonePage from "components/StandalonePage";
|
import StandalonePage from "components/StandalonePage";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
@ -14,13 +13,6 @@ export default function AuthFailure() {
|
|||||||
<div className="flex flex-col items-center justify-center h-full space-y-4">
|
<div className="flex flex-col items-center justify-center h-full space-y-4">
|
||||||
<div className="text-3xl font-bold text-gray-200">You have to be authorized</div>
|
<div className="text-3xl font-bold text-gray-200">You have to be authorized</div>
|
||||||
<div className="text-2xl text-gray-400">to access techpal dashboard</div>
|
<div className="text-2xl text-gray-400">to access techpal dashboard</div>
|
||||||
<Button
|
|
||||||
variant="red"
|
|
||||||
type="fill"
|
|
||||||
href={process.env.REACT_APP_OPENID_PROVIDER_URL}
|
|
||||||
>
|
|
||||||
Войти
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</StandalonePage>
|
</StandalonePage>
|
||||||
);
|
);
|
||||||
|
@ -15,7 +15,6 @@ import AvailabilityIndicator from "components/indicators/AvailabilityIndicator";
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Icons */
|
/* Icons */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGArrowRightShortIcon } from "assets/svg/arrow-right-short.svg";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Dashboard page */
|
/* Dashboard page */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -25,7 +24,7 @@ import { useServicesViewModel } from "services/controller/servicesViewModel";
|
|||||||
import CircleLoader from "components/CircleLoader";
|
import CircleLoader from "components/CircleLoader";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { useUIStore } from "ui/data/uiSlice";
|
import { useUIStore } from "ui/data/uiSlice";
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useSubscriptionsStore } from "subscriptions/data/subscriptionsSlice";
|
import { useSubscriptionsStore } from "subscriptions/data/subscriptionsSlice";
|
||||||
import { useSubscriptionsViewModel } from "subscriptions/controller/subscriptionsViewModel";
|
import { useSubscriptionsViewModel } from "subscriptions/controller/subscriptionsViewModel";
|
||||||
@ -64,13 +63,7 @@ export default function Dashboard() {
|
|||||||
</HexagonOutlined>
|
</HexagonOutlined>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow">
|
<div className="flex-grow">
|
||||||
<Button
|
|
||||||
variant="emerald"
|
|
||||||
type="outline"
|
|
||||||
onClick={() => navigate("/services")}
|
|
||||||
>
|
|
||||||
Connect service
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-20 opacity-40">
|
<div className="pl-20 opacity-40">
|
||||||
@ -84,7 +77,7 @@ export default function Dashboard() {
|
|||||||
className="font-semibold inline-flex items-center space-x-2 hover:space-x-3"
|
className="font-semibold inline-flex items-center space-x-2 hover:space-x-3"
|
||||||
>
|
>
|
||||||
<span className="transition-all">connect</span>
|
<span className="transition-all">connect</span>
|
||||||
<SVGArrowRightShortIcon className="w-3 h-3 fill-white transition-all" />
|
|
||||||
</TextAction>
|
</TextAction>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@ -128,7 +121,6 @@ export default function Dashboard() {
|
|||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<TextAction className="font-semibold inline-flex items-center space-x-2 hover:space-x-3">
|
<TextAction className="font-semibold inline-flex items-center space-x-2 hover:space-x-3">
|
||||||
<span className="transition-all">open</span>
|
<span className="transition-all">open</span>
|
||||||
<SVGArrowRightShortIcon className="w-3 h-3 fill-white transition-all" />
|
|
||||||
</TextAction>
|
</TextAction>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@ -175,7 +167,6 @@ export default function Dashboard() {
|
|||||||
className="font-semibold inline-flex items-center space-x-2 hover:space-x-3"
|
className="font-semibold inline-flex items-center space-x-2 hover:space-x-3"
|
||||||
>
|
>
|
||||||
<span className="transition-all">open</span>
|
<span className="transition-all">open</span>
|
||||||
<SVGArrowRightShortIcon className="w-3 h-3 fill-white transition-all" />
|
|
||||||
</TextAction>
|
</TextAction>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -9,7 +9,6 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Components */
|
/* Components */
|
||||||
import Button from "components/controls/Button";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Misc */
|
/* Misc */
|
||||||
@ -17,7 +16,6 @@ import Button from "components/controls/Button";
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Icons */
|
/* Icons */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGBackIcon } from "assets/svg/backstab.svg";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Account information management page */
|
/* Account information management page */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -33,23 +31,7 @@ const NoMatch = (): JSX.Element => {
|
|||||||
<div className="font-bold text-6xl text-gray-500">404</div>
|
<div className="font-bold text-6xl text-gray-500">404</div>
|
||||||
<div className="font-bold text-3xl mb-10">Page Not Found</div>
|
<div className="font-bold text-3xl mb-10">Page Not Found</div>
|
||||||
<div className="font-thin text-xl mb-10">{t('serv.noSuchPath')}</div>
|
<div className="font-thin text-xl mb-10">{t('serv.noSuchPath')}</div>
|
||||||
<Button
|
|
||||||
iconed={true}
|
|
||||||
htmlType="button"
|
|
||||||
variant="blue"
|
|
||||||
onClick={() =>
|
|
||||||
navigate("/", {
|
|
||||||
replace: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<div className="flex-none w-6 h-6">
|
|
||||||
<SVGBackIcon className="w-full h-full stroke-current opacity-60" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">{t("serv.goHome")}</div>
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,12 +6,9 @@ import Modal from "components/containers/modal/Modal";
|
|||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Icons/SVG */
|
/* Icons/SVG */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGSearchIcon } from "assets/svg/search.svg";
|
|
||||||
import { ReactComponent as SVGTimesIcon } from "assets/svg/times.svg";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Components */
|
/* Components */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import Button from "components/controls/Button";
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Hooks */
|
/* Hooks */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -36,28 +33,7 @@ export default function GlobalSearchbar() {
|
|||||||
<Combobox value="" onChange={() => {}}>
|
<Combobox value="" onChange={() => {}}>
|
||||||
<div className="flex space-x-2 -mt-3 -mx-5 items-center">
|
<div className="flex space-x-2 -mt-3 -mx-5 items-center">
|
||||||
<div className="flex-none basis-5">
|
<div className="flex-none basis-5">
|
||||||
<SVGSearchIcon className="w-full h-full stroke-current" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-grow">
|
|
||||||
<Combobox.Input
|
|
||||||
onChange={(event) => {}}
|
|
||||||
placeholder={t('search.label')}
|
|
||||||
className="bg-transparent
|
|
||||||
focus:outline-none
|
|
||||||
px-4 py-2 w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex-none">
|
|
||||||
<Button
|
|
||||||
htmlType="button"
|
|
||||||
iconed="only"
|
|
||||||
className="w-10 h-10"
|
|
||||||
variant="blue"
|
|
||||||
type="text"
|
|
||||||
onClick={hideSearchbar}
|
|
||||||
>
|
|
||||||
<SVGTimesIcon className="w-full h-full stroke-current" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Combobox.Options>
|
<Combobox.Options>
|
||||||
|
@ -12,12 +12,10 @@ import { useEmailDataViewModel } from "../controller/emailDataViewModel";
|
|||||||
/* Components */
|
/* Components */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import Modal from "components/containers/modal/Modal";
|
import Modal from "components/containers/modal/Modal";
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import InputField from "components/controls/InputField";
|
import InputField from "components/controls/InputField";
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Icons */
|
/* Icons */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
import { ReactComponent as SVGCircleProgressIcon } from "assets/svg/circle-progress.svg";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Component */
|
/* Component */
|
||||||
@ -60,7 +58,6 @@ export default function EmailEditor({ isShown, onClose: extOnClose }: Props) {
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
||||||
<form onSubmit={onSubmitHandler}>
|
<form onSubmit={onSubmitHandler}>
|
||||||
<Modal.CloseButton onClose={onClose} />
|
|
||||||
<Modal.Header>{t("account.mail")}</Modal.Header>
|
<Modal.Header>{t("account.mail")}</Modal.Header>
|
||||||
<InputField
|
<InputField
|
||||||
name="email"
|
name="email"
|
||||||
@ -71,27 +68,7 @@ export default function EmailEditor({ isShown, onClose: extOnClose }: Props) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<Modal.Footer className="flex justify-between">
|
<Modal.Footer className="flex justify-between">
|
||||||
<Button type="text" variant="red" onClick={onClose}>
|
|
||||||
{t("cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={!isValid || isSubmiting}
|
|
||||||
htmlType="submit"
|
|
||||||
type="fill"
|
|
||||||
variant="blue"
|
|
||||||
glowing={true}
|
|
||||||
className="relative"
|
|
||||||
>
|
|
||||||
<span className={classNames({ "opacity-0": isSubmiting })}>
|
|
||||||
{t("save")}
|
|
||||||
</span>
|
|
||||||
<SVGCircleProgressIcon
|
|
||||||
className={classNames(
|
|
||||||
"absolute top-1/2 left-1/2 trasnform -translate-x-1/2 -translate-y-1/2 w-8 h-8 stroke-current",
|
|
||||||
{ "opacity-0": !isSubmiting }
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -3,7 +3,6 @@ import Modal from "components/containers/modal/Modal";
|
|||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import InputField from "components/controls/InputField";
|
import InputField from "components/controls/InputField";
|
||||||
import Button from "components/controls/Button";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isShown: boolean;
|
isShown: boolean;
|
||||||
@ -28,7 +27,6 @@ export default function PasswordConfirmation({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
||||||
<Modal.CloseButton onClose={onClose} />
|
|
||||||
<Modal.Header>{t("dialogues.confirmAction.title")}</Modal.Header>
|
<Modal.Header>{t("dialogues.confirmAction.title")}</Modal.Header>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={{
|
initialValues={{
|
||||||
@ -59,7 +57,6 @@ export default function PasswordConfirmation({
|
|||||||
{t("dialogues.confirmAction.description")}
|
{t("dialogues.confirmAction.description")}
|
||||||
</div>
|
</div>
|
||||||
<Modal.Footer className="text-center">
|
<Modal.Footer className="text-center">
|
||||||
<Button type="outline" htmlType="submit" variant="red">{t('dialogues.confirmAction.confirm')}</Button>
|
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Modal from "components/containers/modal/Modal";
|
import Modal from "components/containers/modal/Modal";
|
||||||
import Button from "components/controls/Button";
|
|
||||||
import InputField from "components/controls/InputField";
|
import InputField from "components/controls/InputField";
|
||||||
import { useUserStore } from "../data/userSlice";
|
import { useUserStore } from "../data/userSlice";
|
||||||
|
|
||||||
import { ReactComponent as SVGCircleProgressIcon } from "assets/svg/circle-progress.svg";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
@ -38,7 +36,6 @@ export default function PersonalInfomrationEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
<Modal isOpen={isShown} onClose={onClose} className="max-w-lg">
|
||||||
<Modal.CloseButton onClose={onClose} />
|
|
||||||
<Modal.Header>{t("account.info")}</Modal.Header>
|
<Modal.Header>{t("account.info")}</Modal.Header>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={{
|
initialValues={{
|
||||||
@ -97,31 +94,7 @@ export default function PersonalInfomrationEditor({
|
|||||||
touched={formik.touched.lastname}
|
touched={formik.touched.lastname}
|
||||||
/>
|
/>
|
||||||
<Modal.Footer className="flex justify-between">
|
<Modal.Footer className="flex justify-between">
|
||||||
<Button type="text" variant="red" onClick={onClose}>
|
|
||||||
{t("cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={
|
|
||||||
!formik.isValid || formik.isSubmitting || !formik.touched
|
|
||||||
}
|
|
||||||
htmlType="submit"
|
|
||||||
type="fill"
|
|
||||||
variant="blue"
|
|
||||||
glowing={true}
|
|
||||||
className="relative"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={classNames({ "opacity-0": formik.isSubmitting })}
|
|
||||||
>
|
|
||||||
{t("save")}
|
|
||||||
</span>
|
|
||||||
<SVGCircleProgressIcon
|
|
||||||
className={classNames(
|
|
||||||
"absolute top-1/2 left-1/2 trasnform -translate-x-1/2 -translate-y-1/2 w-8 h-8 stroke-current",
|
|
||||||
{ "opacity-0": !formik.isSubmitting }
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user