style: new buttons added (#470)

This commit is contained in:
Aaryan Khandelwal 2023-03-17 10:40:38 +05:30 committed by GitHub
parent 4de0abfc22
commit e7ef6275cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 392 additions and 633 deletions

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
// ui
import { CheckCircleIcon } from "@heroicons/react/20/solid";
import { Button, Input } from "components/ui";
import { Input, SecondaryButton } from "components/ui";
// services
import authenticationService from "services/authentication.service";
import useToast from "hooks/use-toast";
@ -140,8 +140,8 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
/>
<button
type="button"
className={`text-xs mt-5 w-full flex justify-end outline-none ${
isResendDisabled ? "text-gray-400 cursor-default" : "cursor-pointer text-theme"
className={`mt-5 flex w-full justify-end text-xs outline-none ${
isResendDisabled ? "cursor-default text-gray-400" : "cursor-pointer text-theme"
} `}
onClick={() => {
setIsCodeResending(true);
@ -169,16 +169,16 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
)}
<div>
{codeSent ? (
<Button
<SecondaryButton
type="submit"
className="w-full text-center"
onClick={handleSubmit(handleSignin)}
disabled={isSubmitting || (!isValid && isDirty)}
loading={isSubmitting || (!isValid && isDirty)}
>
{isSubmitting ? "Signing in..." : "Sign in"}
</Button>
</SecondaryButton>
) : (
<Button
<SecondaryButton
type="submit"
className="w-full text-center"
onClick={() => {
@ -186,10 +186,10 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
setResendCodeTimer(30);
});
}}
disabled={isSubmitting || (!isValid && isDirty)}
loading={isSubmitting || (!isValid && isDirty)}
>
{isSubmitting ? "Sending code..." : "Send code"}
</Button>
</SecondaryButton>
)}
</div>
</form>

View File

@ -1,13 +1,15 @@
import React from "react";
// next
import Link from "next/link";
// react hook form
import { useForm } from "react-hook-form";
// ui
import { Button, Input } from "components/ui";
// services
import authenticationService from "services/authentication.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Input, SecondaryButton } from "components/ui";
// types
type EmailPasswordFormValues = {
email: string;
@ -97,13 +99,13 @@ export const EmailPasswordForm = ({ onSuccess }: any) => {
</div>
</div>
<div className="mt-5">
<Button
disabled={isSubmitting || (!isValid && isDirty)}
className="w-full text-center"
<SecondaryButton
type="submit"
className="w-full text-center"
loading={isSubmitting || (!isValid && isDirty)}
>
{isSubmitting ? "Signing in..." : "Sign In"}
</Button>
</SecondaryButton>
</div>
</form>
</>

View File

@ -20,7 +20,7 @@ import { CreateUpdateIssueModal } from "components/issues";
import { CreateUpdateCycleModal } from "components/cycles";
import { CreateUpdateModuleModal } from "components/modules";
// ui
import { Button } from "components/ui";
import { SecondaryButton } from "components/ui";
// icons
import {
FolderIcon,
@ -350,11 +350,7 @@ export const CommandPalette: React.FC = () => {
</Combobox>
<div className="flex items-center justify-end gap-2 p-3">
<div>
<Button type="button" size="sm" onClick={handleCommandPaletteClose}>
Close
</Button>
</div>
<SecondaryButton onClick={handleCommandPaletteClose}>Close</SecondaryButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -13,7 +13,7 @@ import issuesServices from "services/issues.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { DangerButton, SecondaryButton } from "components/ui";
// icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons";
@ -211,17 +211,10 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
{filteredIssues.length > 0 && (
<div className="flex items-center justify-end gap-2 p-3">
<Button type="button" theme="secondary" size="sm" onClick={handleClose}>
Close
</Button>
<Button
onClick={handleSubmit(handleDelete)}
theme="danger"
size="sm"
disabled={isSubmitting}
>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleSubmit(handleDelete)} loading={isSubmitting}>
{isSubmitting ? "Deleting..." : "Delete selected issues"}
</Button>
</DangerButton>
</div>
)}
</form>

View File

@ -1,14 +1,15 @@
import React, { useState } from "react";
// headless ui
import { Combobox, Dialog, Transition } from "@headlessui/react";
// react-hook-form
import { Controller, SubmitHandler, useForm } from "react-hook-form";
// hooks
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
import useToast from "hooks/use-toast";
// headless ui
// ui
import { Button } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons";
// types
import { IIssue } from "types";
@ -180,17 +181,10 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
/>
{filteredIssues.length > 0 && (
<div className="flex items-center justify-end gap-2 p-3">
<Button type="button" theme="secondary" size="sm" onClick={handleClose}>
Cancel
</Button>
<Button
type="button"
size="sm"
onClick={handleSubmit(onSubmit)}
disabled={isSubmitting}
>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={handleSubmit(onSubmit)} loading={isSubmitting}>
{isSubmitting ? "Adding..." : "Add selected issues"}
</Button>
</PrimaryButton>
</div>
)}
</form>

View File

@ -13,8 +13,7 @@ import { Tab, Transition, Popover } from "@headlessui/react";
import fileService from "services/file.service";
// components
import { Input, Spinner } from "components/ui";
import { PrimaryButton } from "components/ui/button/primary-button";
import { Input, Spinner, PrimaryButton } from "components/ui";
// hooks
import useOutsideClickDetector from "hooks/use-outside-click-detector";

View File

@ -3,16 +3,16 @@ import React, { useCallback, useState } from "react";
import NextImage from "next/image";
import { useRouter } from "next/router";
// react-dropzone
import { useDropzone } from "react-dropzone";
// headless ui
import { Transition, Dialog } from "@headlessui/react";
// services
import fileServices from "services/file.service";
// icon
import { UserCircleIcon } from "components/icons";
// ui
import { Button } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { UserCircleIcon } from "components/icons";
type TImageUploadModalProps = {
value?: string | null;
@ -39,12 +39,7 @@ export const ImageUploadModal: React.FC<TImageUploadModalProps> = ({
setImage(acceptedFiles[0]);
}, []);
const {
getRootProps,
getInputProps,
isDragActive,
open: openFileDialog,
} = useDropzone({
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
});
@ -158,16 +153,10 @@ export const ImageUploadModal: React.FC<TImageUploadModalProps> = ({
</div>
</div>
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button
type="submit"
onClick={handleSubmit}
disabled={isImageUploading || image === null}
>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={handleSubmit} loading={isImageUploading || !image}>
{isImageUploading ? "Uploading..." : "Upload & Save"}
</Button>
</PrimaryButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -18,6 +18,8 @@ import { AllLists, AllBoards } from "components/core";
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
import { CreateUpdateViewModal } from "components/views";
// ui
import { EmptySpace, EmptySpaceItem, PrimaryButton } from "components/ui";
// icons
import { PlusIcon, RectangleStackIcon, TrashIcon, XMarkIcon } from "@heroicons/react/24/outline";
// helpers
@ -27,7 +29,6 @@ import {
CycleIssueResponse,
IIssue,
IIssueFilterOptions,
IView,
ModuleIssueResponse,
UserAuth,
} from "types";
@ -41,8 +42,6 @@ import {
PROJECT_MEMBERS,
STATE_LIST,
} from "constants/fetch-keys";
import { EmptySpace, EmptySpaceItem } from "components/ui";
import { PrimaryButton } from "components/ui/button/primary-button";
type Props = {
type?: "issue" | "cycle" | "module";
@ -501,14 +500,12 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
{Object.keys(filters).length > 0 && (
<PrimaryButton
type="button"
onClick={() =>
setCreateViewModal({
query: filters,
})
}
className="flex items-center gap-4 text-sm"
size="sm"
className="flex items-center gap-2 text-sm"
>
<PlusIcon className="h-4 w-4" />
Save view

View File

@ -1,15 +1,11 @@
import React from "react";
import { useRouter } from "next/router";
import { mutate } from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui
import { Button, Input } from "components/ui";
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// types
import type { IIssueLink, ModuleLink } from "types";
@ -116,12 +112,10 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={onClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={handleSubmit(onSubmit)} loading={isSubmitting}>
{isSubmitting ? "Adding Link..." : "Add Link"}
</Button>
</PrimaryButton>
</div>
</form>
</Dialog.Panel>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useState } from "react";
// next
import { useRouter } from "next/router";
// swr
@ -10,7 +10,7 @@ import cycleService from "services/cycles.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { DangerButton, SecondaryButton } from "components/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@ -28,7 +28,6 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
setIsOpen,
data,
}) => {
const cancelButtonRef = useRef(null);
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@ -68,12 +67,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -121,25 +115,11 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Deleting..." : "Delete"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -1,18 +1,19 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
// toast
import useToast from "hooks/use-toast";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// ui
import { Button, CustomDatePicker, CustomSelect, Input, TextArea } from "components/ui";
// types
import { ICycle } from "types";
// services
import cyclesService from "services/cycles.service";
// helper
// hooks
import useToast from "hooks/use-toast";
// ui
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// helpers
import { getDateRangeStatus } from "helpers/date-time.helper";
// types
import { ICycle } from "types";
type Props = {
handleFormSubmit: (values: Partial<ICycle>) => Promise<void>;
@ -188,11 +189,8 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton
type="submit"
className={
checkEmptyDate
@ -201,7 +199,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
? "cursor-pointer"
: "cursor-not-allowed"
}
disabled={isSubmitting || checkEmptyDate ? false : isDateValid ? false : true}
loading={isSubmitting || checkEmptyDate ? false : isDateValid ? false : true}
>
{status
? isSubmitting
@ -210,7 +208,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
: isSubmitting
? "Creating Cycle..."
: "Create Cycle"}
</Button>
</PrimaryButton>
</div>
</form>
);

View File

@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
import { Button } from "components/ui";
import { SecondaryButton, DangerButton } from "components/ui";
// types
import type { CycleIssueResponse, IIssue, ModuleIssueResponse } from "types";
// fetch-keys
@ -26,7 +26,6 @@ type Props = {
};
export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data }) => {
const cancelButtonRef = useRef(null);
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@ -98,7 +97,7 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" initialFocus={cancelButtonRef} onClose={onClose}>
<Dialog as="div" className="relative z-20" onClose={onClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -136,34 +135,20 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
</span>
</div>
<span>
<p className="text-sm leading-7 text-gray-500 break-all">
<p className="break-all text-sm leading-7 text-gray-500">
Are you sure you want to delete issue{" "}
<span className="font-semibold break-all">
<span className="break-all font-semibold">
{data?.project_detail.identifier}-{data?.sequence_id}
</span>{" "}
? All of the data related to the issue will be permanently removed. This
action cannot be undone.
</p>
</span>
<div className="flex flex-row-reverse items-center gap-3">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="rounded-lg border-none px-5 py-2 "
>
<div className="flex justify-end gap-2">
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Deleting..." : "Delete Issue"}
</Button>
<Button
type="button"
theme="secondary"
className="rounded-lg border-none px-5 py-2 "
onClick={onClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</div>
</Dialog.Panel>

View File

@ -20,8 +20,7 @@ import { CreateStateModal } from "components/states";
import { CreateUpdateCycleModal } from "components/cycles";
import { CreateLabelModal } from "components/labels";
// ui
import { Button, CustomMenu, Input, Loader } from "components/ui";
import { PrimaryButton } from "components/ui/button/primary-button";
import { CustomMenu, Input, Loader, PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { XMarkIcon } from "@heroicons/react/24/outline";
// helpers
@ -355,10 +354,8 @@ export const IssueForm: FC<IssueFormProps> = ({
</button>
</div>
<div className="flex items-center gap-2">
<Button type="button" theme="secondary" onClick={handleClose}>
Discard
</Button>
<PrimaryButton type="submit" size="sm" loading={isSubmitting}>
<SecondaryButton onClick={handleClose}>Discard</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{status
? isSubmitting
? "Updating Issue..."

View File

@ -5,7 +5,7 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
// icons
import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
// ui
import { Button } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// types
import { IIssue } from "types";
import { LayerDiagonalIcon } from "components/icons";
@ -145,12 +145,8 @@ export const ParentIssuesListModal: React.FC<Props> = ({
)}
</Combobox>
<div className="flex items-center justify-end gap-2 p-3">
<Button type="button" theme="danger" size="sm" onClick={handleClose}>
Cancel
</Button>
<Button type="button" size="sm" onClick={() => onChange(values)}>
Add issues
</Button>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={() => onChange(values)}>Add issues</PrimaryButton>
</div>
</>
) : (

View File

@ -14,7 +14,7 @@ import useToast from "hooks/use-toast";
// services
import issuesService from "services/issues.service";
// ui
import { Button } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { BlockedIcon, LayerDiagonalIcon } from "components/icons";
@ -270,14 +270,10 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
{filteredIssues.length > 0 && (
<div className="flex items-center justify-end gap-2 p-3">
<div>
<Button type="button" theme="secondary" size="sm" onClick={handleClose}>
Close
</Button>
</div>
<Button onClick={handleSubmit(onSubmit)} size="sm">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={handleSubmit(onSubmit)}>
Add selected issues
</Button>
</PrimaryButton>
</div>
)}
</form>

View File

@ -14,7 +14,7 @@ import useToast from "hooks/use-toast";
// services
import issuesServices from "services/issues.service";
// ui
import { Button } from "components/ui";
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
import { BlockerIcon, LayerDiagonalIcon } from "components/icons";
@ -270,14 +270,10 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
{filteredIssues.length > 0 && (
<div className="flex items-center justify-end gap-2 p-3">
<div>
<Button type="button" theme="secondary" size="sm" onClick={handleClose}>
Close
</Button>
</div>
<Button onClick={handleSubmit(onSubmit)} size="sm">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton onClick={handleSubmit(onSubmit)}>
Add selected issues
</Button>
</PrimaryButton>
</div>
)}
</Dialog.Panel>

View File

@ -29,7 +29,7 @@ import {
SidebarStateSelect,
} from "components/issues";
// ui
import { Input, Button, Spinner, CustomDatePicker } from "components/ui";
import { Input, Spinner, CustomDatePicker } from "components/ui";
// icons
import {
TagIcon,
@ -581,12 +581,20 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
}}
autoComplete="off"
/>
<Button type="submit" theme="danger" onClick={() => setCreateLabelForm(false)}>
<button
type="submit"
className="grid place-items-center rounded bg-red-500 p-2.5"
onClick={() => setCreateLabelForm(false)}
>
<XMarkIcon className="h-4 w-4 text-white" />
</Button>
<Button type="submit" theme="success" disabled={isSubmitting}>
</button>
<button
type="submit"
className="grid place-items-center rounded bg-green-500 p-2.5"
disabled={isSubmitting}
>
<PlusIcon className="h-4 w-4 text-white" />
</Button>
</button>
</form>
)}
</div>

View File

@ -210,7 +210,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, userAuth }) => {
<a className="group flex items-center justify-between gap-2 rounded p-2 hover:bg-gray-100">
<div className="flex items-center gap-2 rounded text-xs">
<span
className="block flex-shrink-0 h-1.5 w-1.5 rounded-full"
className="block h-1.5 w-1.5 flex-shrink-0 rounded-full"
style={{
backgroundColor: issue.state_detail.color,
}}
@ -224,7 +224,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, userAuth }) => {
{!isNotAllowed && (
<button
type="button"
className="opacity-0 group-hover:opacity-100 cursor-pointer"
className="cursor-pointer opacity-0 group-hover:opacity-100"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -253,6 +253,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, userAuth }) => {
}
optionsPosition="left"
noBorder
noChevron
>
<CustomMenu.MenuItem onClick={handleCreateIssueModal}>Create new</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setSubIssuesListModal(true)}>

View File

@ -13,7 +13,7 @@ import { Dialog, Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
// ui
import { Button, Input } from "components/ui";
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types
@ -171,12 +171,10 @@ export const CreateLabelModal: React.FC<Props> = ({ isOpen, projectId, handleClo
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={onClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Creating Label..." : "Create Label"}
</Button>
</PrimaryButton>
</div>
</form>
</Dialog.Panel>

View File

@ -13,7 +13,7 @@ import { Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
// ui
import { Button, Input } from "components/ui";
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// types
import { IIssueLabels } from "types";
// fetch-keys
@ -168,24 +168,22 @@ export const CreateUpdateLabelInline: React.FC<Props> = ({
error={errors.name}
/>
</div>
<Button
type="button"
theme="secondary"
<SecondaryButton
onClick={() => {
reset();
setLabelForm(false);
}}
>
Cancel
</Button>
</SecondaryButton>
{isUpdating ? (
<Button type="button" onClick={handleSubmit(handleLabelUpdate)} disabled={isSubmitting}>
<PrimaryButton onClick={handleSubmit(handleLabelUpdate)} loading={isSubmitting}>
{isSubmitting ? "Updating" : "Update"}
</Button>
</PrimaryButton>
) : (
<Button type="button" onClick={handleSubmit(handleLabelCreate)} disabled={isSubmitting}>
<PrimaryButton onClick={handleSubmit(handleLabelCreate)} loading={isSubmitting}>
{isSubmitting ? "Adding" : "Add"}
</Button>
</PrimaryButton>
)}
</div>
);

View File

@ -11,7 +11,7 @@ import modulesService from "services/modules.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { SecondaryButton, DangerButton } from "components/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@ -29,14 +29,10 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
const {
query: { workspaceSlug },
} = router;
const { workspaceSlug } = router.query;
const { setToastAlert } = useToast();
const cancelButtonRef = useRef(null);
const handleClose = () => {
setIsOpen(false);
setIsDeleteLoading(false);
@ -67,12 +63,7 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -120,25 +111,11 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Deleting..." : "Delete"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -5,7 +5,7 @@ import { Controller, useForm } from "react-hook-form";
// components
import { ModuleLeadSelect, ModuleMembersSelect, ModuleStatusSelect } from "components/modules";
// ui
import { Button, CustomDatePicker, Input, TextArea } from "components/ui";
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// types
import { IModule } from "types";
@ -132,10 +132,8 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{status
? isSubmitting
? "Updating Module..."
@ -143,7 +141,7 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
: isSubmitting
? "Creating Module..."
: "Create Module"}
</Button>
</PrimaryButton>
</div>
</form>
);

View File

@ -10,7 +10,7 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button, Loader } from "components/ui";
import { DangerButton, Loader, SecondaryButton } from "components/ui";
// icons
import GithubLogo from "public/logos/github-square.png";
// types
@ -133,19 +133,13 @@ const OAuthPopUp = ({ integration }: any) => {
{workspaceIntegrations ? (
isInstalled ? (
<Button
theme="danger"
size="rg"
className="text-xs"
onClick={handleRemoveIntegration}
disabled={deletingIntegration}
>
<DangerButton onClick={handleRemoveIntegration} loading={deletingIntegration}>
{deletingIntegration ? "Removing..." : "Remove installation"}
</Button>
</DangerButton>
) : (
<Button theme="secondary" size="rg" className="text-xs" onClick={startAuth}>
<SecondaryButton onClick={startAuth} outline>
Add installation
</Button>
</SecondaryButton>
)
) : (
<Loader>

View File

@ -4,7 +4,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
import { Button } from "components/ui";
import { SecondaryButton, DangerButton } from "components/ui";
type Props = {
isOpen: boolean;
@ -16,8 +16,6 @@ type Props = {
const ConfirmProjectMemberRemove: React.FC<Props> = ({ isOpen, onClose, data, handleDelete }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const cancelButtonRef = useRef(null);
const handleClose = () => {
onClose();
setIsDeleteLoading(false);
@ -31,12 +29,7 @@ const ConfirmProjectMemberRemove: React.FC<Props> = ({ isOpen, onClose, data, ha
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -84,25 +77,11 @@ const ConfirmProjectMemberRemove: React.FC<Props> = ({ isOpen, onClose, data, ha
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Removing..." : "Remove"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -15,8 +15,7 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { PrimaryButton } from "components/ui/button/primary-button";
import { Button, Input, TextArea, CustomSelect } from "components/ui";
import { Input, TextArea, CustomSelect, PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { XMarkIcon } from "@heroicons/react/24/outline";
// components
@ -311,9 +310,7 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
</div>
<div className="mt-5 flex justify-end gap-2 border-t-2 px-4 py-3">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" size="sm" loading={isSubmitting}>
{isSubmitting ? "Adding project..." : "Add Project"}
</PrimaryButton>

View File

@ -11,7 +11,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
import { Button, Input } from "components/ui";
import { DangerButton, Input, SecondaryButton } from "components/ui";
// types
import type { IProject, IWorkspace } from "types";
// fetch-keys
@ -24,10 +24,12 @@ type TConfirmProjectDeletionProps = {
data: IProject | null;
};
export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = (props) => {
const { isOpen, data, onClose, onSuccess } = props;
const cancelButtonRef = useRef(null);
export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = ({
isOpen,
data,
onClose,
onSuccess,
}) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [confirmProjectName, setConfirmProjectName] = useState("");
const [confirmDeleteMyProject, setConfirmDeleteMyProject] = useState(false);
@ -84,12 +86,7 @@ export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = (props
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -168,25 +165,11 @@ export const DeleteProjectModal: React.FC<TConfirmProjectDeletionProps> = (props
name="typeDelete"
/>
</div>
<div className="flex flex-row-reverse items-center gap-3">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading || !canDelete}
className="rounded-lg border-none px-5 py-2"
>
<div className="flex justify-end gap-2">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading || !canDelete}>
{isDeleteLoading ? "Deleting..." : "Delete Project"}
</Button>
<Button
type="button"
theme="secondary"
className="rounded-lg border-none px-5 py-2"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</div>
</Dialog.Panel>

View File

@ -1,10 +1,11 @@
import React, { useState } from "react";
// headless ui
import { Transition, Dialog } from "@headlessui/react";
// ui
import { PrimaryButton, SecondaryButton } from "components/ui";
// types
import type { IProject } from "types";
import { Button } from "components/ui";
// type
type TJoinProjectModalProps = {
@ -70,12 +71,10 @@ export const JoinProjectModal: React.FC<TJoinProjectModalProps> = ({ onClose, on
<div className="space-y-3" />
</div>
<div className="mt-5 flex justify-end gap-2">
<Button type="button" theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" onClick={handleJoin} disabled={isJoiningLoading}>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" onClick={handleJoin} loading={isJoiningLoading}>
{isJoiningLoading ? "Joining..." : "Join Project"}
</Button>
</PrimaryButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -1,6 +1,7 @@
import { FC } from "react";
// ui
import { Button } from "components/ui";
import { SecondaryButton } from "components/ui";
export interface JoinProjectProps {
isJoiningProject: boolean;
@ -16,9 +17,9 @@ export const JoinProject: FC<JoinProjectProps> = ({ isJoiningProject, handleJoin
below.
</p>
<div>
<Button type="button" disabled={isJoiningProject} onClick={handleJoin}>
<SecondaryButton loading={isJoiningProject} onClick={handleJoin}>
{isJoiningProject ? "Joining..." : "Click to join"}
</Button>
</SecondaryButton>
</div>
</div>
</div>

View File

@ -8,7 +8,7 @@ import { useForm, Controller } from "react-hook-form";
import { Dialog, Transition } from "@headlessui/react";
// ui
import { Button, CustomSelect, TextArea } from "components/ui";
import { CustomSelect, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// hooks
import useToast from "hooks/use-toast";
// services
@ -218,12 +218,10 @@ const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, member
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Sending Invitation..." : "Send Invitation"}
</Button>
</PrimaryButton>
</div>
</form>
</Dialog.Panel>

View File

@ -1,14 +1,15 @@
// react
import React, { useState } from "react";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// react-color
import { TwitterPicker } from "react-color";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// ui
import { PencilIcon, RectangleGroupIcon } from "@heroicons/react/24/outline";
import { TwitterPicker } from "react-color";
import { Button, CustomMenu, Input } from "components/ui";
import { CustomMenu, Input, PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { PencilIcon, RectangleGroupIcon } from "@heroicons/react/24/outline";
// types
import { IIssueLabels } from "types";
@ -110,19 +111,15 @@ const SingleLabel: React.FC<Props> = ({ label, issueLabels, editLabel, handleLab
id="labelName"
name="name"
register={register}
placeholder="Lable title"
placeholder="Label title"
validations={{
required: "Label title is required",
}}
error={errors.name}
/>
</div>
<Button type="button" theme="secondary" onClick={() => setNewLabelForm(false)}>
Cancel
</Button>
<Button type="button" disabled={isSubmitting}>
{isSubmitting ? "Adding" : "Add"}
</Button>
<SecondaryButton onClick={() => setNewLabelForm(false)}>Cancel</SecondaryButton>
<PrimaryButton loading={isSubmitting}>{isSubmitting ? "Adding" : "Add"}</PrimaryButton>
</div>
</div>
) : (

View File

@ -13,7 +13,7 @@ import { Dialog, Popover, Transition } from "@headlessui/react";
// services
import stateService from "services/state.service";
// ui
import { Button, CustomSelect, Input, TextArea } from "components/ui";
import { CustomSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types
@ -215,12 +215,10 @@ export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClo
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={onClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Creating State..." : "Create State"}
</Button>
</PrimaryButton>
</div>
</form>
</Dialog.Panel>

View File

@ -15,7 +15,7 @@ import stateService from "services/state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button, CustomSelect, Input } from "components/ui";
import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
// types
import type { IState } from "types";
// fetch-keys
@ -217,12 +217,10 @@ export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, select
error={errors.description}
autoComplete="off"
/>
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button theme="primary" disabled={isSubmitting} type="submit">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
</Button>
</PrimaryButton>
</form>
);
};

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
@ -14,7 +14,7 @@ import issuesServices from "services/issues.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { DangerButton, SecondaryButton } from "components/ui";
// helpers
import { groupBy } from "helpers/array.helper";
// types
@ -46,8 +46,6 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
: null
);
const cancelButtonRef = useRef(null);
const handleClose = () => {
onClose();
setIsDeleteLoading(false);
@ -82,12 +80,7 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -143,25 +136,14 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading || issuesWithThisStateExist}
className="inline-flex sm:ml-3"
loading={isDeleteLoading || issuesWithThisStateExist}
>
{isDeleteLoading ? "Deleting..." : "Delete"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -1,62 +0,0 @@
import * as React from "react";
type ButtonProps = {
onClick?: () => void;
children: React.ReactNode;
type?: "button" | "submit" | "reset";
className?: string;
theme?: "primary" | "secondary" | "success" | "danger";
size?: "sm" | "rg" | "md" | "lg";
disabled?: boolean;
largePadding?: boolean;
};
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
children,
onClick,
type = "button",
size = "sm",
className = "",
theme = "primary",
disabled = false,
largePadding,
},
ref
) => (
<button
ref={ref}
onClick={onClick}
type={type}
disabled={disabled}
className={`inline-flex items-center justify-center rounded font-medium duration-300 ${
theme === "primary"
? `${
disabled ? "opacity-70" : ""
} border border-transparent bg-gray-200 shadow-sm hover:bg-gray-300 focus:outline-none`
: theme === "secondary"
? "border border-gray-300 bg-transparent hover:bg-gray-200"
: theme === "success"
? `${
disabled ? "opacity-70" : ""
} border border-transparent bg-green-500 text-white shadow-sm hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500`
: `${
disabled ? "opacity-70" : ""
} border border-transparent bg-red-500 text-white shadow-sm hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500`
} ${
size === "sm"
? "p-2 text-xs"
: size === "md"
? "text-md px-3 py-2"
: size === "lg"
? "text-md px-4 py-2"
: "px-2.5 py-2 text-sm"
} ${largePadding ? "px-8" : ""} ${className}`}
>
{children}
</button>
)
);
Button.displayName = "Button";

View File

@ -1 +0,0 @@
export * from "./primary-button";

View File

@ -1,32 +0,0 @@
type TButtonProps = {
children: React.ReactNode;
className?: string;
onClick?: () => void;
type?: "button" | "submit" | "reset";
disabled?: boolean;
loading?: boolean;
size?: "sm" | "md" | "lg";
};
export const PrimaryButton: React.FC<TButtonProps> = (props) => {
const { children, className, onClick, type, disabled, loading, size = "md" } = props;
return (
<button
type={type}
className={`hover:bg-opacity-90 transition-colors text-white rounded-lg ${
size === "sm"
? "px-2.5 py-1.5 text-sm"
: size === "md"
? "px-3 py-2 text-base"
: "px-4 py-3 text-lg"
} ${disabled ? "bg-gray-400 cursor-not-allowed" : "bg-theme"} ${className || ""} ${
loading ? "cursor-wait" : ""
}`}
onClick={onClick}
disabled={disabled || loading}
>
<div className="flex items-center">{children}</div>
</button>
);
};

View File

@ -0,0 +1,36 @@
// types
import { ButtonProps } from "./type";
export const DangerButton: React.FC<ButtonProps> = ({
children,
className = "",
onClick,
type = "button",
disabled = false,
loading = false,
size = "sm",
outline = false,
}) => (
<button
type={type}
className={`${className} border border-red-500 font-medium duration-300 ${
size === "sm"
? "rounded px-3 py-2 text-xs"
: size === "md"
? "rounded-md px-3.5 py-2 text-sm"
: "rounded-lg px-4 py-2 text-base"
} ${
disabled
? "cursor-not-allowed border-gray-300 bg-gray-300 text-black hover:border-gray-300 hover:border-opacity-100 hover:bg-gray-300 hover:bg-opacity-100 hover:text-black"
: ""
} ${
outline
? "bg-transparent hover:bg-red-500 hover:text-white"
: "bg-red-500 text-white hover:border-opacity-90 hover:bg-opacity-90"
} ${loading ? "cursor-wait" : ""}`}
onClick={onClick}
disabled={disabled || loading}
>
{children}
</button>
);

View File

@ -0,0 +1,3 @@
export * from "./danger-button";
export * from "./primary-button";
export * from "./secondary-button";

View File

@ -0,0 +1,36 @@
// types
import { ButtonProps } from "./type";
export const PrimaryButton: React.FC<ButtonProps> = ({
children,
className = "",
onClick,
type = "button",
disabled = false,
loading = false,
size = "sm",
outline = false,
}) => (
<button
type={type}
className={`${className} border border-theme font-medium duration-300 ${
size === "sm"
? "rounded px-3 py-2 text-xs"
: size === "md"
? "rounded-md px-3.5 py-2 text-sm"
: "rounded-lg px-4 py-2 text-base"
} ${
disabled
? "cursor-not-allowed border-gray-300 bg-gray-300 text-black hover:border-gray-300 hover:border-opacity-100 hover:bg-gray-300 hover:bg-opacity-100 hover:text-black"
: ""
} ${
outline
? "bg-transparent hover:bg-theme hover:text-white"
: "bg-theme text-white hover:border-opacity-90 hover:bg-opacity-90"
} ${loading ? "cursor-wait" : ""}`}
onClick={onClick}
disabled={disabled || loading}
>
{children}
</button>
);

View File

@ -0,0 +1,36 @@
// types
import { ButtonProps } from "./type";
export const SecondaryButton: React.FC<ButtonProps> = ({
children,
className = "",
onClick,
type = "button",
disabled = false,
loading = false,
size = "sm",
outline = false,
}) => (
<button
type={type}
className={`${className} border border-gray-300 font-medium duration-300 ${
size === "sm"
? "rounded px-3 py-2 text-xs"
: size === "md"
? "rounded-md px-3.5 py-2 text-sm"
: "rounded-lg px-4 py-2 text-base"
} ${
disabled
? "cursor-not-allowed border-gray-300 bg-gray-300 hover:border-gray-300 hover:border-opacity-100 hover:bg-gray-300 hover:bg-opacity-100"
: ""
} ${
outline
? "bg-transparent hover:bg-gray-300"
: "bg-gray-300 hover:border-opacity-90 hover:bg-opacity-90"
} ${loading ? "cursor-wait" : ""}`}
onClick={onClick}
disabled={disabled || loading}
>
{children}
</button>
);

View File

@ -0,0 +1,10 @@
export type ButtonProps = {
children: React.ReactNode;
className?: string;
onClick?: () => void;
type?: "button" | "submit" | "reset";
disabled?: boolean;
loading?: boolean;
size?: "sm" | "md" | "lg";
outline?: boolean;
};

View File

@ -1,7 +1,7 @@
export * from "./buttons";
export * from "./input";
export * from "./text-area";
export * from "./avatar";
export * from "./button";
export * from "./context-menu";
export * from "./custom-menu";
export * from "./custom-search-select";

View File

@ -11,7 +11,7 @@ import viewsService from "services/views.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { DangerButton, SecondaryButton } from "components/ui";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
@ -34,8 +34,6 @@ export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, onClose, onSucc
const { setToastAlert } = useToast();
const cancelButtonRef = useRef(null);
const handleClose = () => {
setIsDeleteLoading(false);
onClose();
@ -74,12 +72,7 @@ export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, onClose, onSucc
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -127,25 +120,11 @@ export const DeleteViewModal: React.FC<Props> = ({ isOpen, data, onClose, onSucc
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Deleting..." : "Delete"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -3,7 +3,7 @@ import { useEffect } from "react";
// react-hook-form
import { useForm } from "react-hook-form";
// ui
import { Button, Input, TextArea } from "components/ui";
import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// types
import { IView } from "types";
@ -97,10 +97,8 @@ export const ViewForm: React.FC<Props> = ({
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{status
? isSubmitting
? "Updating View..."
@ -108,7 +106,7 @@ export const ViewForm: React.FC<Props> = ({
: isSubmitting
? "Creating View..."
: "Create View"}
</Button>
</PrimaryButton>
</div>
</form>
);

View File

@ -1,10 +1,10 @@
import React, { useRef, useState } from "react";
import React, { useState } from "react";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
import { Button } from "components/ui";
import { DangerButton, SecondaryButton } from "components/ui";
type Props = {
isOpen: boolean;
@ -16,8 +16,6 @@ type Props = {
const ConfirmWorkspaceMemberRemove: React.FC<Props> = ({ isOpen, onClose, data, handleDelete }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const cancelButtonRef = useRef(null);
const handleClose = () => {
onClose();
setIsDeleteLoading(false);
@ -31,12 +29,7 @@ const ConfirmWorkspaceMemberRemove: React.FC<Props> = ({ isOpen, onClose, data,
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -84,25 +77,11 @@ const ConfirmWorkspaceMemberRemove: React.FC<Props> = ({ isOpen, onClose, data,
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
{isDeleteLoading ? "Removing..." : "Remove"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// ui
import { Button, Input } from "components/ui";
import { DangerButton, Input, SecondaryButton } from "components/ui";
// types
import type { IWorkspace } from "types";
// fetch-keys
@ -26,7 +26,6 @@ type Props = {
};
export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose }) => {
const cancelButtonRef = useRef(null);
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [confirmProjectName, setConfirmProjectName] = useState("");
const [confirmDeleteMyProject, setConfirmDeleteMyProject] = useState(false);
@ -77,12 +76,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose })
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
initialFocus={cancelButtonRef}
onClose={handleClose}
>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
@ -166,25 +160,11 @@ export const DeleteWorkspaceModal: React.FC<Props> = ({ isOpen, data, onClose })
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<Button
type="button"
onClick={handleDeletion}
theme="danger"
disabled={isDeleteLoading || !canDelete}
className="inline-flex sm:ml-3"
>
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton onClick={handleDeletion} loading={isDeleteLoading || !canDelete}>
{isDeleteLoading ? "Deleting..." : "Delete"}
</Button>
<Button
type="button"
theme="secondary"
className="inline-flex sm:ml-3"
onClick={handleClose}
ref={cancelButtonRef}
>
Cancel
</Button>
</DangerButton>
</div>
</Dialog.Panel>
</Transition.Child>

View File

@ -6,7 +6,7 @@ import { Dialog, Transition } from "@headlessui/react";
// services
import workspaceService from "services/workspace.service";
// ui
import { Button, CustomSelect, Input } from "components/ui";
import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
// hooks
import useToast from "hooks/use-toast";
// types
@ -153,12 +153,10 @@ const SendWorkspaceInvitationModal: React.FC<Props> = ({
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Sending Invitation..." : "Send Invitation"}
</Button>
</PrimaryButton>
</div>
</form>
</Dialog.Panel>

View File

@ -1,5 +1,3 @@
// ui
import { Button } from "components/ui";
// icons
import { Bars3Icon } from "@heroicons/react/24/outline";
@ -14,14 +12,13 @@ const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar })
<div className="flex w-full flex-row items-center justify-between gap-y-4 border-b bg-white px-5 py-4 ">
<div className="flex items-center gap-2">
<div className="block md:hidden">
<Button
<button
type="button"
theme="secondary"
className="h-8 w-8"
className="grid h-8 w-8 place-items-center rounded border border-gray-300"
onClick={() => setToggleSidebar((prevData) => !prevData)}
>
<Bars3Icon className="h-5 w-5" />
</Button>
</button>
</div>
{breadcrumbs}
{left}

View File

@ -10,7 +10,7 @@ import projectService from "services/project.service";
// hooks
import useUser from "hooks/use-user";
// ui
import { Button, Spinner } from "components/ui";
import { SecondaryButton, Spinner } from "components/ui";
// components
import { NotAuthorizedView } from "components/core";
import { CommandPalette } from "components/command-palette";
@ -103,17 +103,13 @@ const AppLayout: FC<AppLayoutProps> = ({
actionButton={
(memberType?.isViewer || memberType?.isGuest) && projectId ? (
<Link href={`/${workspaceSlug}/projects/${projectId}/issues`}>
<Button size="sm" theme="secondary">
Go to Issues
</Button>
<SecondaryButton>Go to Issues</SecondaryButton>
</Link>
) : (
(memberType?.isViewer || memberType?.isGuest) &&
workspaceSlug && (
<Link href={`/${workspaceSlug}`}>
<Button size="sm" theme="secondary">
Go to workspace
</Button>
<SecondaryButton>Go to workspace</SecondaryButton>
</Link>
)
)

View File

@ -6,7 +6,7 @@ import Image from "next/image";
// layouts
import DefaultLayout from "layouts/default-layout";
// ui
import { Button } from "components/ui";
import { SecondaryButton } from "components/ui";
// images
import Image404 from "public/404.svg";
// types
@ -33,9 +33,7 @@ const PageNotFound: NextPage = () => (
</div>
<Link href="/">
<a className="block">
<Button type="button" largePadding>
Go to Home
</Button>
<SecondaryButton size="md">Go to Home</SecondaryButton>
</a>
</Link>
</div>

View File

@ -18,7 +18,7 @@ import AppLayout from "layouts/app-layout";
// components
import { ImageUploadModal } from "components/core";
// ui
import { Button, Input, Spinner } from "components/ui";
import { DangerButton, Input, SecondaryButton, Spinner } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import {
@ -205,24 +205,17 @@ const Profile: NextPage = () => {
<br />
Supported file types are .jpg and .png.
</p>
<div className="flex items-center gap-2">
<Button
type="button"
className="mt-4"
onClick={() => setIsImageUploadModalOpen(true)}
>
<div className="mt-4 flex items-center gap-2">
<SecondaryButton onClick={() => setIsImageUploadModalOpen(true)}>
Upload new
</Button>
</SecondaryButton>
{myProfile.avatar && myProfile.avatar !== "" && (
<Button
type="button"
className="mt-4"
theme="danger"
<DangerButton
onClick={() => handleDelete(myProfile.avatar, true)}
disabled={isRemoving}
loading={isRemoving}
>
{isRemoving ? "Removing..." : "Remove"}
</Button>
</DangerButton>
)}
</div>
</div>
@ -269,9 +262,9 @@ const Profile: NextPage = () => {
</div>
{isEditing && (
<div>
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Updating Profile..." : "Update Profile"}
</Button>
</SecondaryButton>
</div>
)}
</form>

View File

@ -16,7 +16,7 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button, CustomSelect, Loader } from "components/ui";
import { CustomSelect, Loader, SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import { IProject, IWorkspace } from "types";
@ -239,9 +239,9 @@ const ControlSettings: NextPage<TControlSettingsProps> = (props) => {
</div>
</div>
<div className="sm:text-right">
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Updating Project..." : "Update Project"}
</Button>
</SecondaryButton>
</div>
</div>
</form>

View File

@ -13,14 +13,15 @@ import AppLayout from "layouts/app-layout";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "components/ui";
import { SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { ContrastIcon, PeopleGroupIcon, ViewListIcon } from "components/icons";
// types
import { IProject, UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next";
// fetch-keys
import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
import { ContrastIcon, PeopleGroupIcon, ViewListIcon } from "components/icons";
const FeaturesSettings: NextPage<UserAuth> = (props) => {
const router = useRouter();
@ -183,14 +184,10 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
</div>
<div className="flex items-center gap-2">
<a href="https://plane.so/" target="_blank" rel="noreferrer">
<Button theme="secondary" size="rg" className="text-xs">
Plane is open-source, view Roadmap
</Button>
<SecondaryButton outline>Plane is open-source, view Roadmap</SecondaryButton>
</a>
<a href="https://github.com/makeplane/plane" target="_blank" rel="noreferrer">
<Button theme="secondary" size="rg" className="text-xs">
Star us on GitHub
</Button>
<SecondaryButton outline>Star us on GitHub</SecondaryButton>
</a>
</div>
</section>

View File

@ -20,7 +20,14 @@ import EmojiIconPicker from "components/emoji-icon-picker";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button, Input, TextArea, Loader, CustomSelect, OutlineButton } from "components/ui";
import {
Input,
TextArea,
Loader,
CustomSelect,
OutlineButton,
SecondaryButton,
} from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// helpers
import { debounce } from "helpers/common.helper";
@ -30,7 +37,6 @@ import type { NextPage, GetServerSidePropsContext } from "next";
import { PROJECTS_LIST, PROJECT_DETAILS, WORKSPACE_DETAILS } from "constants/fetch-keys";
// constants
import { NETWORK_CHOICES } from "constants/project";
import SettingsNavbar from "layouts/settings-navbar";
const defaultValues: Partial<IProject> = {
name: "",
@ -288,9 +294,9 @@ const GeneralSettings: NextPage<UserAuth> = (props) => {
</div>
<div className="sm:text-right">
{projectDetails ? (
<Button type="submit" disabled={isSubmitting}>
<SecondaryButton type="submit" loading={isSubmitting}>
{isSubmitting ? "Updating Project..." : "Update Project"}
</Button>
</SecondaryButton>
) : (
<Loader className="mt-2 w-full">
<Loader.Item height="34px" width="100px" light />

View File

@ -19,7 +19,7 @@ import {
SingleLabelGroup,
} from "components/labels";
// ui
import { Loader } from "components/ui";
import { Loader, PrimaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
@ -28,7 +28,6 @@ import { IIssueLabels, UserAuth } from "types";
import type { GetServerSidePropsContext, NextPage } from "next";
// fetch-keys
import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
import { PrimaryButton } from "components/ui/button/primary-button";
const LabelsSettings: NextPage<UserAuth> = (props) => {
const { isMember, isOwner, isViewer, isGuest } = props;

View File

@ -11,7 +11,7 @@ import workspaceService from "services/workspace.service";
// layouts
import AppLayout from "layouts/app-layout";
// ui
import { Button } from "components/ui";
import { SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import type { NextPage, GetServerSideProps } from "next";
@ -66,9 +66,7 @@ const BillingSettings: NextPage<TBillingSettingsProps> = (props) => {
<h4 className="text-md mb-1 leading-6 text-gray-900">Current plan</h4>
<p className="mb-3 text-sm text-gray-500">You are currently using the free plan</p>
<a href="https://plane.so/pricing" target="_blank" rel="noreferrer">
<Button theme="secondary" size="rg" className="text-xs">
View Plans and Upgrade
</Button>
<SecondaryButton outline>View Plans and Upgrade</SecondaryButton>
</a>
</div>
<div>

View File

@ -23,7 +23,7 @@ import AppLayout from "layouts/app-layout";
import { ImageUploadModal } from "components/core";
import { DeleteWorkspaceModal } from "components/workspace";
// ui
import { Spinner, Button, Input, CustomSelect, OutlineButton } from "components/ui";
import { Spinner, Input, CustomSelect, OutlineButton, SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
@ -168,13 +168,13 @@ const WorkspaceSettings: NextPage<UserAuth> = (props) => {
)}
</button>
<div>
<Button
<SecondaryButton
onClick={() => {
setIsImageUploadModalOpen(true);
}}
>
{isImageUploading ? "Uploading..." : "Upload"}
</Button>
</SecondaryButton>
</div>
</div>
</div>
@ -195,9 +195,7 @@ const WorkspaceSettings: NextPage<UserAuth> = (props) => {
value={`app.plane.so/${activeWorkspace.slug}`}
disabled
/>
<Button
type="button"
theme="secondary"
<SecondaryButton
className="h-min"
onClick={() =>
copyTextToClipboard(`https://app.plane.so/${activeWorkspace.slug}`).then(() => {
@ -208,9 +206,10 @@ const WorkspaceSettings: NextPage<UserAuth> = (props) => {
});
})
}
outline
>
<LinkIcon className="h-[18px] w-[18px]" />
</Button>
</SecondaryButton>
</div>
</div>
<div className="grid grid-cols-12 gap-4 sm:gap-16">
@ -259,9 +258,9 @@ const WorkspaceSettings: NextPage<UserAuth> = (props) => {
</div>
</div>
<div className="sm:text-right">
<Button onClick={handleSubmit(onSubmit)} disabled={isSubmitting}>
<SecondaryButton onClick={handleSubmit(onSubmit)} loading={isSubmitting}>
{isSubmitting ? "Updating..." : "Update Workspace"}
</Button>
</SecondaryButton>
</div>
<div className="grid grid-cols-12 gap-4 sm:gap-16">
<div className="col-span-12 sm:col-span-6">

View File

@ -15,7 +15,7 @@ import DefaultLayout from "layouts/default-layout";
// components
import SingleInvitation from "components/workspace/single-invitation";
// ui
import { Button, Spinner, EmptySpace, EmptySpaceItem } from "components/ui";
import { Spinner, EmptySpace, EmptySpaceItem, SecondaryButton, PrimaryButton } from "components/ui";
// icons
import { CubeIcon, PlusIcon } from "@heroicons/react/24/outline";
// types
@ -112,14 +112,12 @@ const OnBoard: NextPage = () => {
<div className="mt-6 flex items-center gap-2">
<Link href="/">
<a className="w-full">
<Button className="w-full" theme="secondary">
Go to Home
</Button>
<SecondaryButton className="w-full">Go to Home</SecondaryButton>
</a>
</Link>
<Button className="w-full" onClick={submitInvitations}>
<PrimaryButton className="w-full" onClick={submitInvitations}>
Accept and Continue
</Button>
</PrimaryButton>
</div>
</div>
) : workspaces && workspaces.length > 0 ? (