style: issue modal select attributes

This commit is contained in:
Aaryan Khandelwal 2023-09-19 19:04:54 +05:30
parent 9ef30b4fbf
commit 5dc9e00c3d
12 changed files with 84 additions and 60 deletions

View File

@ -5,6 +5,7 @@ import { ICustomAttribute } from "types";
type Props = {
attributeDetails: ICustomAttribute;
className?: string;
issueId: string;
projectId: string;
value: Date | undefined;
@ -22,12 +23,15 @@ const TIME_FORMATS: { [key: string]: string } = {
"24": "HH:mm",
};
export const CustomDateTimeAttribute: React.FC<Props> = ({ attributeDetails, onChange, value }) => (
export const CustomDateTimeAttribute: React.FC<Props> = (props) => {
const { attributeDetails, className = "", onChange, value } = props;
return (
<div className="flex-shrink-0">
<ReactDatePicker
selected={value}
onChange={onChange}
className="bg-custom-background-80 rounded text-xs px-2.5 py-0.5 outline-none truncate"
className={`bg-custom-background-80 rounded text-xs px-2.5 py-0.5 outline-none truncate ${className}`}
calendarClassName="!bg-custom-background-80"
dateFormat={`${
attributeDetails.extra_settings.hide_date
@ -44,3 +48,4 @@ export const CustomDateTimeAttribute: React.FC<Props> = ({ attributeDetails, onC
/>
</div>
);
};

View File

@ -13,12 +13,13 @@ import useWorkspaceDetails from "hooks/use-workspace-details";
import { getFileIcon } from "components/icons";
import { X } from "lucide-react";
// helpers
import { getFileExtension, getFileName } from "helpers/attachment.helper";
import { getFileExtension } from "helpers/attachment.helper";
// types
import { ICustomAttribute } from "types";
type Props = {
attributeDetails: ICustomAttribute;
className?: string;
issueId: string;
projectId: string;
value: string | undefined;
@ -28,7 +29,7 @@ type Props = {
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB
export const CustomFileAttribute: React.FC<Props> = (props) => {
const { attributeDetails, onChange, value } = props;
const { attributeDetails, className = "", onChange, value } = props;
const [isUploading, setIsUploading] = useState(false);
@ -136,7 +137,7 @@ export const CustomFileAttribute: React.FC<Props> = (props) => {
{...getRootProps()}
className={`flex items-center bg-custom-background-80 text-xs rounded px-2.5 py-0.5 cursor-pointer truncate w-min max-w-full whitespace-nowrap ${
isDragActive ? "bg-custom-primary-100/10" : ""
} ${isDragReject ? "bg-red-500/10" : ""}`}
} ${isDragReject ? "bg-red-500/10" : ""} ${className}`}
>
<input className="flex-shrink-0" {...getInputProps()} />
<span className={`flex-grow truncate text-left ${fileError ? "text-red-500" : ""}`}>

View File

@ -15,9 +15,12 @@ import { Search } from "lucide-react";
import { ICustomAttribute } from "types";
// 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 = {
attributeDetails: ICustomAttribute;
className?: string;
issueId: string;
projectId: string;
value: string | undefined;
@ -26,6 +29,7 @@ type Props = {
export const CustomRelationAttribute: React.FC<Props> = ({
attributeDetails,
className = "",
onChange,
projectId,
value,
@ -54,17 +58,30 @@ export const CustomRelationAttribute: React.FC<Props> = ({
: null
);
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId);
const optionsList =
attributeDetails.unit === "cycle"
? cycles?.map((c) => ({ id: c.id, name: c.name }))
? cycles?.map((c) => ({ id: c.id, query: c.name, label: c.name }))
: attributeDetails.unit === "module"
? modules?.map((m) => ({ id: m.id, name: m.name }))
? modules?.map((m) => ({ id: m.id, query: m.name, label: m.name }))
: attributeDetails.unit === "user"
? members?.map((m) => ({
id: m.member.id,
query: m.member.display_name,
label: (
<div className="flex items-center gap-2">
<Avatar user={m.member} />
{m.member.is_bot ? m.member.first_name : m.member.display_name}
</div>
),
}))
: [];
const selectedOption = (optionsList ?? []).find((option) => option.id === value);
const options = (optionsList ?? []).filter((option) =>
option.name.toLowerCase().includes(query.toLowerCase())
option.query.toLowerCase().includes(query.toLowerCase())
);
return (
@ -76,8 +93,10 @@ export const CustomRelationAttribute: React.FC<Props> = ({
>
{({ open }: { open: boolean }) => (
<>
<Combobox.Button 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">
{selectedOption?.name ?? `Select ${attributeDetails.unit}`}
<Combobox.Button
className={`lex 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}`}
</Combobox.Button>
<Transition
show={open}
@ -109,7 +128,7 @@ export const CustomRelationAttribute: React.FC<Props> = ({
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"
>
<span className="px-1 rounded-sm truncate">{option.name}</span>
{option.label}
</Combobox.Option>
))
) : (

View File

@ -11,6 +11,7 @@ import { ICustomAttribute } from "types";
type Props = {
attributeDetails: ICustomAttribute;
className?: string;
issueId: string;
onChange: (val: string | string[] | undefined) => void;
projectId: string;
@ -23,7 +24,7 @@ type Props = {
);
export const CustomSelectAttribute: React.FC<Props> = (props) => {
const { attributeDetails, multiple = false, onChange, value } = props;
const { attributeDetails, className = "", multiple = false, onChange, value } = props;
const [isOpen, setIsOpen] = useState(false);
const [query, setQuery] = useState("");
@ -31,10 +32,6 @@ export const CustomSelectAttribute: React.FC<Props> = (props) => {
const dropdownButtonRef = useRef<HTMLButtonElement>(null);
const dropdownOptionsRef = useRef<HTMLUListElement>(null);
const selectedOption =
attributeDetails.children.find((option) => option.id === value) ??
attributeDetails.children.find((option) => option.is_default);
const options = attributeDetails.children.filter((option) =>
option.display_name.toLowerCase().includes(query.toLowerCase())
);
@ -118,7 +115,9 @@ export const CustomSelectAttribute: React.FC<Props> = (props) => {
})}
</div>
) : (
<div className="text-xs px-2.5 py-0.5 rounded bg-custom-background-80">
<div
className={`text-xs px-2.5 py-0.5 rounded bg-custom-background-80 ${className}`}
>
Select {attributeDetails.display_name}
</div>
)
@ -148,7 +147,9 @@ export const CustomSelectAttribute: React.FC<Props> = (props) => {
</div>
)
) : (
<div className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded">
<div
className={`cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded ${className}`}
>
Select {attributeDetails.display_name}
</div>
)}

View File

@ -28,15 +28,11 @@ export const RelationAttributeForm: React.FC<FormComponentProps> = ({ control })
optionsClassName="w-full"
input
>
{CUSTOM_ATTRIBUTE_UNITS.map((unit) => {
if (unit.value === "user") return null;
return (
{CUSTOM_ATTRIBUTE_UNITS.map((unit) => (
<CustomSelect.Option key={unit.value} value={unit.value}>
{unit.label}
</CustomSelect.Option>
);
})}
))}
</CustomSelect>
)}
/>

View File

@ -77,7 +77,7 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
<div className="flex items-center justify-between gap-2">
<Disclosure.Button className="font-medium flex items-center gap-2">
<ChevronDown
className={`transition-all ${open ? "-rotate-90" : ""}`}
className={`transition-all ${open ? "" : "-rotate-90"}`}
size={14}
strokeWidth={1.5}
/>
@ -119,7 +119,7 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
</>
)}
</Disclosure>
<div className="flex items-center gap-1 flex-wrap mt-3.5">
<div className="flex items-center gap-2 flex-wrap mt-3.5">
{Object.entries(nonDescriptionFields).map(([attributeId, attribute]) => (
<div key={attributeId}>
{attribute.type === "checkbox" && (
@ -134,6 +134,7 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
{attribute.type === "datetime" && (
<CustomDateTimeAttribute
attributeDetails={attribute}
className="bg-transparent border border-custom-border-200 py-1"
issueId={issueId}
onChange={(val) =>
onChange(attribute.id, val ? [val.toISOString()] : undefined)
@ -147,15 +148,17 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
{attribute.type === "file" && (
<CustomFileAttribute
attributeDetails={attribute}
className="bg-transparent border border-custom-border-200 py-1"
issueId={issueId}
onChange={(val) => onChange(attribute.id, val)}
projectId={projectId}
value={undefined}
value={values[attribute.id]?.[0]}
/>
)}
{attribute.type === "multi_select" && (
<CustomSelectAttribute
attributeDetails={attribute}
className="bg-transparent border border-custom-border-200 py-1"
issueId={issueId}
onChange={(val) => onChange(attribute.id, val)}
projectId={projectId}
@ -166,6 +169,7 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
{attribute.type === "relation" && (
<CustomRelationAttribute
attributeDetails={attribute}
className="bg-transparent border border-custom-border-200 py-1"
issueId={issueId}
onChange={(val) => onChange(attribute.id, val)}
projectId={projectId}
@ -175,6 +179,7 @@ export const IssueModalCustomAttributesList: React.FC<Props> = observer((props)
{attribute.type === "select" && (
<CustomSelectAttribute
attributeDetails={attribute}
className="bg-transparent border border-custom-border-200 py-1"
issueId={issueId}
onChange={(val) => onChange(attribute.id, val)}
projectId={projectId}

View File

@ -42,17 +42,14 @@ export const ObjectsSelect: React.FC<Props> = observer(({ onChange, projectId, v
return (
<CustomSearchSelect
customButton={
<button type="button" className="bg-custom-background-80 rounded text-xs px-2.5 py-0.5">
{entities?.find((e) => e.id === value)?.display_name ?? "Default"}
</button>
}
label={entities?.find((e) => e.id === value)?.display_name ?? "Default"}
value={value}
maxHeight="md"
optionsClassName="!min-w-[10rem]"
onChange={onChange}
options={options}
position="right"
noChevron
/>
);
});

View File

@ -49,7 +49,7 @@ export const IssueAssigneeSelect: React.FC<Props> = ({ projectId, value = [], on
<AssigneesList userIds={value} length={3} showLength={true} />
</div>
) : (
<div className="flex items-center justify-center gap-2 px-1.5 py-1 rounded shadow-sm border border-custom-border-300 hover:bg-custom-background-80">
<div className="flex items-center justify-center gap-2 px-1.5 py-1 rounded shadow-sm border border-custom-border-200 hover:bg-custom-background-80">
<Icon iconName="person" className="!text-base !leading-4" />
<span className="text-custom-text-200">Assignee</span>
</div>

View File

@ -19,7 +19,7 @@ export const IssueDateSelect: React.FC<Props> = ({ label, maxDate, minDate, onCh
<Popover className="relative flex items-center justify-center rounded-lg">
{({ close }) => (
<>
<Popover.Button className="flex cursor-pointer items-center rounded-md border border-custom-border-200 text-xs shadow-sm duration-200">
<Popover.Button className="flex cursor-pointer items-center rounded border border-custom-border-200 text-xs shadow-sm duration-200">
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs text-custom-text-200 hover:bg-custom-background-80">
{value ? (
<>

View File

@ -69,7 +69,7 @@ export const IssueLabelSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
/>
</span>
) : (
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs rounded shadow-sm border border-custom-border-300 hover:bg-custom-background-80">
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs rounded shadow-sm border border-custom-border-200 hover:bg-custom-background-80">
<TagIcon className="h-3.5 w-3.5 text-custom-text-200" />
<span className=" text-custom-text-200">Label</span>
</span>

View File

@ -78,7 +78,7 @@ export const CustomSearchSelect = ({
) : (
<Combobox.Button
type="button"
className={`flex items-center justify-between gap-1 w-full rounded-md shadow-sm border border-custom-border-300 duration-300 focus:outline-none ${
className={`flex items-center justify-between gap-1 w-full rounded shadow-sm border border-custom-border-200 duration-300 focus:outline-none ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
disabled

View File

@ -45,7 +45,7 @@ const CustomSelect = ({
) : (
<Listbox.Button
type="button"
className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-300 shadow-sm duration-300 focus:outline-none ${
className={`flex items-center justify-between gap-1 w-full rounded border border-custom-border-200 shadow-sm duration-300 focus:outline-none ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
disabled