forked from github/plane
style: finished module card design (#593)
* style: finished modulecard design * fix: use assignee list component
This commit is contained in:
parent
c75ca8203f
commit
5c1607f39b
@ -43,6 +43,7 @@ export * from "./user-icon";
|
||||
export * from "./grid-view-icons";
|
||||
export * from "./assignment-clipboard-icon";
|
||||
export * from "./tick-mark-icon";
|
||||
export * from "./target-icon"
|
||||
export * from "./contrast-icon";
|
||||
export * from "./people-group-icon";
|
||||
export * from "./cmd-icon";
|
||||
|
20
apps/app/components/icons/target-icon.tsx
Normal file
20
apps/app/components/icons/target-icon.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
import type { Props } from "./types";
|
||||
|
||||
export const TargetIcon: React.FC<Props> = ({
|
||||
width = "24",
|
||||
height = "24",
|
||||
className,
|
||||
color = "black",
|
||||
}) => (
|
||||
<svg width={width} height={height} className={className} color={color} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" xlinkHref="http://www.w3.org/1999/xlink">
|
||||
<rect width="16" height="16" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlinkHref="#image0_2094_50417" transform="scale(0.01)"/>
|
||||
</pattern>
|
||||
<image id="image0_2094_50417" width="100" height="100" xlinkHref="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
@ -26,7 +26,7 @@ export const ModuleStatusSelect: React.FC<Props> = ({ control, error }) => (
|
||||
value={value}
|
||||
label={
|
||||
<div
|
||||
className={`flex items-center justify-center gap-2 text-xs ${
|
||||
className={`flex items-center justify-center h-6 gap-2 text-xs ${
|
||||
error ? "text-red-500" : ""
|
||||
}`}
|
||||
>
|
||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import Image from "next/image";
|
||||
|
||||
import { mutate } from "swr";
|
||||
|
||||
@ -15,16 +14,14 @@ import { DeleteModuleModal } from "components/modules";
|
||||
// ui
|
||||
import { AssigneesList, Avatar, CustomMenu, Tooltip } from "components/ui";
|
||||
// icons
|
||||
import User from "public/user.png";
|
||||
import {
|
||||
CalendarDaysIcon,
|
||||
DocumentDuplicateIcon,
|
||||
PencilIcon,
|
||||
StarIcon,
|
||||
TrashIcon,
|
||||
UserCircleIcon,
|
||||
UserGroupIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { CalendarMonthIcon, TargetIcon } from "components/icons";
|
||||
|
||||
// helpers
|
||||
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
||||
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||
@ -121,6 +118,7 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
||||
|
||||
const endDate = new Date(module.target_date ?? "");
|
||||
const startDate = new Date(module.start_date ?? "");
|
||||
const lastUpdated = new Date(module.updated_at ?? "");
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -129,14 +127,14 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
||||
setIsOpen={setModuleDeleteModal}
|
||||
data={module}
|
||||
/>
|
||||
<div className="flex flex-col rounded-[10px] border bg-white text-xs">
|
||||
<div className="flex flex-col overflow-hidden rounded-[10px] divide-y border bg-white text-xs">
|
||||
<div className="p-4">
|
||||
<div className="flex w-full flex-col gap-5">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<Tooltip tooltipContent={module.name} position="top-left">
|
||||
<Link href={`/${workspaceSlug}/projects/${module.project}/modules/${module.id}`}>
|
||||
<a className="w-full">
|
||||
<h3 className="break-all text-lg font-semibold text-black">
|
||||
<a className="w-auto max-w-[calc(100%-9rem)]">
|
||||
<h3 className="break-all text-lg truncate font-semibold text-black">
|
||||
{truncateText(module.name, 75)}
|
||||
</h3>
|
||||
</a>
|
||||
@ -144,7 +142,7 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
||||
</Tooltip>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="mr-2 rounded bg-gray-100 px-2.5 py-2">
|
||||
<div className="mr-2 rounded flex bg-gray-100 px-2.5 py-2">
|
||||
<span className="capitalize">{module?.status?.replace("-", " ")}</span>
|
||||
</div>
|
||||
{module.is_favorite ? (
|
||||
@ -181,62 +179,19 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="flex items-start gap-1">
|
||||
<CalendarDaysIcon className="h-4 w-4 text-gray-900" />
|
||||
<CalendarMonthIcon className="h-4 w-4 text-gray-900" />
|
||||
<span className="text-gray-400">Start:</span>
|
||||
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-1">
|
||||
<CalendarDaysIcon className="h-4 w-4 text-gray-900" />
|
||||
<TargetIcon className="h-4 w-4 text-gray-900" />
|
||||
<span className="text-gray-400">End:</span>
|
||||
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<UserCircleIcon className="h-4 w-4 text-gray-900" />
|
||||
<span className="text-gray-400">Lead:</span>
|
||||
<div>
|
||||
{module.lead_detail ? (
|
||||
<div className="flex items-center gap-1">
|
||||
<Avatar user={module.lead_detail} />
|
||||
<span>{module.lead_detail.first_name}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-1">
|
||||
<Image
|
||||
src={User}
|
||||
height="12px"
|
||||
width="12px"
|
||||
className="rounded-full"
|
||||
alt="N/A"
|
||||
/>
|
||||
<span>N/A</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<UserGroupIcon className="h-4 w-4 text-gray-900" />
|
||||
<span className="text-gray-400">Members:</span>
|
||||
<div className="flex items-center gap-1 text-xs">
|
||||
{module.members && module.members.length > 0 ? (
|
||||
<AssigneesList userIds={module.members} length={3} />
|
||||
) : (
|
||||
<div className="flex items-center gap-1">
|
||||
<Image
|
||||
src={User}
|
||||
height="16px"
|
||||
width="16px"
|
||||
className="rounded-full"
|
||||
alt="N/A"
|
||||
/>
|
||||
<span>N/A</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-full items-end">
|
||||
<div className="flex flex-col h-full items-end">
|
||||
<div className="flex w-full items-center justify-between gap-2 justify-self-end bg-gray-100 p-4">
|
||||
<span>Progress</span>
|
||||
<div className="bar relative h-1 w-full rounded bg-gray-300">
|
||||
@ -249,6 +204,17 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
||||
</div>
|
||||
<span>{isNaN(completionPercentage) ? 0 : completionPercentage.toFixed(0)}%</span>
|
||||
</div>
|
||||
<div className="flex justify-between w-full px-4 pb-4 bg-gray-100 item-center">
|
||||
<p className="text-[#858E96]">
|
||||
Last updated:
|
||||
<span className="text-black font-medium">
|
||||
{renderShortDateWithYearFormat(lastUpdated)}
|
||||
</span>
|
||||
</p>
|
||||
<div className="flex items-center gap-1">
|
||||
<AssigneesList users={module.members_detail} length={4} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user