forked from github/plane
fix: modals layout
This commit is contained in:
parent
8ff1e8dd87
commit
4a5ca4d51b
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
@ -9,14 +9,17 @@ import { Combobox, Transition } from "@headlessui/react";
|
|||||||
// services
|
// services
|
||||||
import cyclesService from "services/cycles.service";
|
import cyclesService from "services/cycles.service";
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
|
// hooks
|
||||||
|
import useProjectMembers from "hooks/use-project-members";
|
||||||
|
import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown";
|
||||||
|
// ui
|
||||||
|
import { Avatar } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import { ICustomAttribute } from "types";
|
import { ICustomAttribute } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CYCLES_LIST, MODULE_LIST } from "constants/fetch-keys";
|
import { CYCLES_LIST, MODULE_LIST } from "constants/fetch-keys";
|
||||||
import useProjectMembers from "hooks/use-project-members";
|
|
||||||
import { Avatar } from "components/ui";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
attributeDetails: ICustomAttribute;
|
attributeDetails: ICustomAttribute;
|
||||||
@ -37,8 +40,12 @@ export const CustomRelationAttribute: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
|
const dropdownButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const dropdownOptionsRef = useRef<HTMLUListElement>(null);
|
||||||
|
|
||||||
const { data: cycles } = useSWR(
|
const { data: cycles } = useSWR(
|
||||||
workspaceSlug && projectId && attributeDetails.unit === "cycle"
|
workspaceSlug && projectId && attributeDetails.unit === "cycle"
|
||||||
? CYCLES_LIST(projectId.toString())
|
? CYCLES_LIST(projectId.toString())
|
||||||
@ -84,64 +91,59 @@ export const CustomRelationAttribute: React.FC<Props> = ({
|
|||||||
option.query.toLowerCase().includes(query.toLowerCase())
|
option.query.toLowerCase().includes(query.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownButtonRef, dropdownOptionsRef);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Combobox
|
<Combobox
|
||||||
as="div"
|
as="div"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val) => onChange(val)}
|
onChange={(val) => onChange(val)}
|
||||||
className="relative flex-shrink-0 text-left"
|
className="flex-shrink-0 text-left flex items-center"
|
||||||
>
|
>
|
||||||
{({ open }: { open: boolean }) => (
|
{({ open }: { open: boolean }) => (
|
||||||
<>
|
<>
|
||||||
<Combobox.Button
|
<Combobox.Button
|
||||||
|
ref={dropdownButtonRef}
|
||||||
className={`flex items-center text-xs rounded px-2.5 py-0.5 truncate w-min max-w-full text-left bg-custom-background-80 ${className}`}
|
className={`flex items-center text-xs rounded px-2.5 py-0.5 truncate w-min max-w-full text-left bg-custom-background-80 ${className}`}
|
||||||
>
|
>
|
||||||
{selectedOption?.label ?? `Select ${attributeDetails.unit}`}
|
{selectedOption?.label ?? `Select ${attributeDetails.unit}`}
|
||||||
</Combobox.Button>
|
</Combobox.Button>
|
||||||
<Transition
|
<Combobox.Options
|
||||||
show={open}
|
ref={dropdownOptionsRef}
|
||||||
as={React.Fragment}
|
className="fixed z-10 border border-custom-border-300 px-2 py-2.5 rounded bg-custom-background-100 text-xs shadow-custom-shadow-rg focus:outline-none w-48 whitespace-nowrap mt-1"
|
||||||
enter="transition ease-out duration-200"
|
|
||||||
enterFrom="opacity-0 translate-y-1"
|
|
||||||
enterTo="opacity-100 translate-y-0"
|
|
||||||
leave="transition ease-in duration-150"
|
|
||||||
leaveFrom="opacity-100 translate-y-0"
|
|
||||||
leaveTo="opacity-0 translate-y-1"
|
|
||||||
>
|
>
|
||||||
<Combobox.Options className="fixed z-10 mb-2 border-[0.5px] border-custom-border-300 p-1 min-w-[10rem] max-h-60 max-w-[10rem] rounded bg-custom-background-100 text-xs shadow-custom-shadow-rg focus:outline-none mt-1 flex flex-col overflow-hidden">
|
<div className="flex w-full items-center justify-start rounded-sm border-[0.6px] border-custom-border-200 bg-custom-background-90 px-2 mb-1">
|
||||||
<div className="flex w-full items-center justify-start rounded-sm border-[0.6px] border-custom-border-200 bg-custom-background-90 px-2 mb-1">
|
<Search className="text-custom-text-400" size={12} strokeWidth={1.5} />
|
||||||
<Search className="text-custom-text-400" size={12} strokeWidth={1.5} />
|
<Combobox.Input
|
||||||
<Combobox.Input
|
className="w-full bg-transparent py-1 px-2 text-xs text-custom-text-200 placeholder:text-custom-text-400 focus:outline-none"
|
||||||
className="w-full bg-transparent py-1 px-2 text-xs text-custom-text-200 placeholder:text-custom-text-400 focus:outline-none"
|
value={query}
|
||||||
value={query}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
placeholder="Type to search..."
|
||||||
placeholder="Type to search..."
|
displayValue={(assigned: any) => assigned?.name}
|
||||||
displayValue={(assigned: any) => assigned?.name}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div className="mt-1 overflow-y-auto">
|
||||||
<div className="mt-1 overflow-y-auto">
|
{options ? (
|
||||||
{options ? (
|
options.length > 0 ? (
|
||||||
options.length > 0 ? (
|
options.map((option) => (
|
||||||
options.map((option) => (
|
<Combobox.Option
|
||||||
<Combobox.Option
|
key={option.id}
|
||||||
key={option.id}
|
value={option.id}
|
||||||
value={option.id}
|
className="flex items-center gap-1 cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-80 w-full"
|
||||||
className="flex items-center gap-1 cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-80 w-full"
|
>
|
||||||
>
|
{option.label}
|
||||||
{option.label}
|
</Combobox.Option>
|
||||||
</Combobox.Option>
|
))
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<p className="text-custom-text-300 text-center py-1">
|
|
||||||
No {attributeDetails.unit}s found
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
) : (
|
) : (
|
||||||
<p className="text-custom-text-300 text-center py-1">Loading...</p>
|
<p className="text-custom-text-300 text-center py-1">
|
||||||
)}
|
No {attributeDetails.unit}s found
|
||||||
</div>
|
</p>
|
||||||
</Combobox.Options>
|
)
|
||||||
</Transition>
|
) : (
|
||||||
|
<p className="text-custom-text-300 text-center py-1">Loading...</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Combobox.Options>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Combobox>
|
</Combobox>
|
||||||
|
@ -125,7 +125,9 @@ export const CustomSelectAttribute: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Combobox.Button>
|
</Combobox.Button>
|
||||||
<div className={`${open ? "fixed z-20 top-0 left-0 h-full w-full cursor-auto" : ""}`}>
|
<div
|
||||||
|
className={`${open ? "fixed z-20 top-0 left-0 h-screen w-screen cursor-auto" : ""}`}
|
||||||
|
>
|
||||||
<Combobox.Options
|
<Combobox.Options
|
||||||
ref={dropdownOptionsRef}
|
ref={dropdownOptionsRef}
|
||||||
className="fixed z-10 border border-custom-border-300 px-2 py-2.5 rounded bg-custom-background-100 text-xs shadow-custom-shadow-rg focus:outline-none w-48 whitespace-nowrap mt-1"
|
className="fixed z-10 border border-custom-border-300 px-2 py-2.5 rounded bg-custom-background-100 text-xs shadow-custom-shadow-rg focus:outline-none w-48 whitespace-nowrap mt-1"
|
||||||
|
@ -145,18 +145,18 @@ export const ObjectModal: React.FC<Props> = observer(
|
|||||||
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 h-full w-full z-20">
|
<Transition.Child
|
||||||
<div className="flex items-center justify-center h-full w-full p-4 sm:p-0">
|
as={React.Fragment}
|
||||||
<Transition.Child
|
enter="ease-out duration-300"
|
||||||
as={React.Fragment}
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
enter="ease-out duration-300"
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leave="ease-in duration-200"
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leave="ease-in duration-200"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
>
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
<Dialog.Panel className="fixed inset-0 h-full w-full z-20">
|
||||||
>
|
<div className="flex items-center justify-center h-full w-full p-4 sm:p-0">
|
||||||
<Dialog.Panel className="bg-custom-background-100 w-1/2 max-h-[85%] flex flex-col rounded-xl">
|
<div className="bg-custom-background-100 w-1/2 max-h-[85%] flex flex-col rounded-xl">
|
||||||
<h3 className="text-2xl font-semibold px-6 pt-5">New Object</h3>
|
<h3 className="text-2xl font-semibold px-6 pt-5">New Object</h3>
|
||||||
<div className="mt-5 space-y-5 h-full overflow-y-auto">
|
<div className="mt-5 space-y-5 h-full overflow-y-auto">
|
||||||
<div className="space-y-4 px-6">
|
<div className="space-y-4 px-6">
|
||||||
@ -253,10 +253,10 @@ export const ObjectModal: React.FC<Props> = observer(
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog.Panel>
|
</div>
|
||||||
</Transition.Child>
|
</div>
|
||||||
</div>
|
</Dialog.Panel>
|
||||||
</div>
|
</Transition.Child>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
);
|
||||||
|
@ -538,18 +538,18 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer(
|
|||||||
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<Transition.Child
|
||||||
<div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-20">
|
as={React.Fragment}
|
||||||
<Transition.Child
|
enter="ease-out duration-300"
|
||||||
as={React.Fragment}
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
enter="ease-out duration-300"
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||||||
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leave="ease-in duration-200"
|
||||||
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leave="ease-in duration-200"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
>
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
<Dialog.Panel className="fixed inset-0 h-full w-full z-20 overflow-y-auto">
|
||||||
>
|
<div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-20">
|
||||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
<div className="relative rounded-lg border border-custom-border-200 bg-custom-background-100 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
||||||
<IssueForm
|
<IssueForm
|
||||||
handleFormSubmit={handleFormSubmit}
|
handleFormSubmit={handleFormSubmit}
|
||||||
initialData={data ?? prePopulateData}
|
initialData={data ?? prePopulateData}
|
||||||
@ -565,10 +565,10 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer(
|
|||||||
handleCustomAttributesChange={handleCustomAttributesChange}
|
handleCustomAttributesChange={handleCustomAttributesChange}
|
||||||
handleFormDirty={handleFormDirty}
|
handleFormDirty={handleFormDirty}
|
||||||
/>
|
/>
|
||||||
</Dialog.Panel>
|
</div>
|
||||||
</Transition.Child>
|
</div>
|
||||||
</div>
|
</Dialog.Panel>
|
||||||
</div>
|
</Transition.Child>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
</>
|
</>
|
||||||
|
@ -102,17 +102,17 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
|||||||
/>
|
/>
|
||||||
<Transition.Root appear show={isSidePeekOpen} as={React.Fragment}>
|
<Transition.Root appear show={isSidePeekOpen} as={React.Fragment}>
|
||||||
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
||||||
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
|
<Transition.Child
|
||||||
<Transition.Child
|
as={React.Fragment}
|
||||||
as={React.Fragment}
|
enter="transition-transform duration-300"
|
||||||
enter="transition-transform duration-300"
|
enterFrom="translate-x-full"
|
||||||
enterFrom="translate-x-full"
|
enterTo="translate-x-0"
|
||||||
enterTo="translate-x-0"
|
leave="transition-transform duration-200"
|
||||||
leave="transition-transform duration-200"
|
leaveFrom="translate-x-0"
|
||||||
leaveFrom="translate-x-0"
|
leaveTo="translate-x-full"
|
||||||
leaveTo="translate-x-full"
|
>
|
||||||
>
|
<Dialog.Panel className="fixed inset-0 z-20 h-full w-full overflow-y-auto">
|
||||||
<Dialog.Panel className="fixed z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
|
<div className="fixed z-20 bg-custom-background-100 top-0 right-0 h-full w-1/2 shadow-custom-shadow-md">
|
||||||
<SidePeekView
|
<SidePeekView
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleDeleteIssue={() => setDeleteIssueModal(true)}
|
handleDeleteIssue={() => setDeleteIssueModal(true)}
|
||||||
@ -123,9 +123,9 @@ export const IssuePeekOverview: React.FC<Props> = observer(
|
|||||||
setMode={(mode) => setPeekOverviewMode(mode)}
|
setMode={(mode) => setPeekOverviewMode(mode)}
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
/>
|
/>
|
||||||
</Dialog.Panel>
|
</div>
|
||||||
</Transition.Child>
|
</Dialog.Panel>
|
||||||
</div>
|
</Transition.Child>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
<Transition.Root appear show={isModalPeekOpen} as={React.Fragment}>
|
<Transition.Root appear show={isModalPeekOpen} as={React.Fragment}>
|
||||||
|
Loading…
Reference in New Issue
Block a user