forked from cerc-io/snowballtools-base
[T-4921: feat] Update project card component (#136)
* 🎨 style: add hover interaction to the card * ⚡️ feat: make the whole card clickable * 🎨 style: adjust hovered background for wavy border * ♻️ refactor: move wavy border class to project card theme * 🎨 style: add transition when hover * 📝 docs: add todo to experiment using `Link` componnt
This commit is contained in:
parent
8ee61c0c85
commit
b1bf47d104
@ -8,6 +8,7 @@ export const projectCardTheme = tv({
|
|||||||
'rounded-2xl',
|
'rounded-2xl',
|
||||||
'flex',
|
'flex',
|
||||||
'flex-col',
|
'flex-col',
|
||||||
|
'group',
|
||||||
],
|
],
|
||||||
upperContent: ['px-4', 'py-4', 'flex', 'items-start', 'gap-3', 'relative'],
|
upperContent: ['px-4', 'py-4', 'flex', 'items-start', 'gap-3', 'relative'],
|
||||||
content: ['flex', 'flex-col', 'gap-1', 'flex-1'],
|
content: ['flex', 'flex-col', 'gap-1', 'flex-1'],
|
||||||
@ -20,13 +21,15 @@ export const projectCardTheme = tv({
|
|||||||
description: ['text-xs', 'text-elements-low-em'],
|
description: ['text-xs', 'text-elements-low-em'],
|
||||||
icons: ['flex', 'items-center', 'gap-1'],
|
icons: ['flex', 'items-center', 'gap-1'],
|
||||||
lowerContent: [
|
lowerContent: [
|
||||||
'bg-surface-card-hovered',
|
'transition-colors',
|
||||||
|
'duration-150',
|
||||||
'px-4',
|
'px-4',
|
||||||
'py-4',
|
'py-4',
|
||||||
'flex',
|
'flex',
|
||||||
'flex-col',
|
'flex-col',
|
||||||
'gap-2',
|
'gap-2',
|
||||||
'rounded-b-2xl',
|
'rounded-b-2xl',
|
||||||
|
'group-hover:bg-surface-card-hovered',
|
||||||
],
|
],
|
||||||
latestDeployment: ['flex', 'items-center', 'gap-2'],
|
latestDeployment: ['flex', 'items-center', 'gap-2'],
|
||||||
deploymentStatusContainer: [
|
deploymentStatusContainer: [
|
||||||
@ -46,6 +49,12 @@ export const projectCardTheme = tv({
|
|||||||
'items-center',
|
'items-center',
|
||||||
'gap-2',
|
'gap-2',
|
||||||
],
|
],
|
||||||
|
wavyBorder: [
|
||||||
|
'bg-surface-card',
|
||||||
|
'transition-colors',
|
||||||
|
'duration-150',
|
||||||
|
'group-hover:bg-surface-card-hovered',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
status: {
|
status: {
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import React, { ComponentPropsWithoutRef, MouseEvent } from 'react';
|
import React, {
|
||||||
|
ComponentPropsWithoutRef,
|
||||||
|
MouseEvent,
|
||||||
|
useCallback,
|
||||||
|
} from 'react';
|
||||||
import { ProjectCardTheme, projectCardTheme } from './ProjectCard.theme';
|
import { ProjectCardTheme, projectCardTheme } from './ProjectCard.theme';
|
||||||
import { Project } from 'gql-client';
|
import { Project } from 'gql-client';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
@ -11,7 +15,7 @@ import {
|
|||||||
WarningDiamondIcon,
|
WarningDiamondIcon,
|
||||||
} from 'components/shared/CustomIcon';
|
} from 'components/shared/CustomIcon';
|
||||||
import { relativeTimeMs } from 'utils/time';
|
import { relativeTimeMs } from 'utils/time';
|
||||||
import { Link } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Avatar } from 'components/shared/Avatar';
|
import { Avatar } from 'components/shared/Avatar';
|
||||||
import { getInitials } from 'utils/geInitials';
|
import { getInitials } from 'utils/geInitials';
|
||||||
import {
|
import {
|
||||||
@ -27,6 +31,8 @@ export interface ProjectCardProps
|
|||||||
project: Project;
|
project: Project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Update the whole component to use `Link` from `react-router-dom` and remove the `useNavigate` hook,
|
||||||
|
// currently it's not possible to use `Link` because the dot menu is not a direct child of the `Link` component
|
||||||
export const ProjectCard = ({
|
export const ProjectCard = ({
|
||||||
className,
|
className,
|
||||||
project,
|
project,
|
||||||
@ -38,14 +44,24 @@ export const ProjectCard = ({
|
|||||||
// TODO: Update this to use the actual status from the API
|
// TODO: Update this to use the actual status from the API
|
||||||
const hasError = status === 'failure';
|
const hasError = status === 'failure';
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleOptionsClick = (
|
const handleOptionsClick = (
|
||||||
e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>,
|
e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>,
|
||||||
) => {
|
) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
navigate(`projects/${project.id}`);
|
||||||
|
}, [project.id, navigate]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...props} className={theme.wrapper({ className })}>
|
<div
|
||||||
|
{...props}
|
||||||
|
className={theme.wrapper({ className })}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
{/* Upper content */}
|
{/* Upper content */}
|
||||||
<div className={theme.upperContent()}>
|
<div className={theme.upperContent()}>
|
||||||
{/* Icon container */}
|
{/* Icon container */}
|
||||||
@ -54,14 +70,13 @@ export const ProjectCard = ({
|
|||||||
imageSrc={project.icon}
|
imageSrc={project.icon}
|
||||||
initials={getInitials(project.name)}
|
initials={getInitials(project.name)}
|
||||||
/>
|
/>
|
||||||
{/* </div> */}
|
|
||||||
{/* Title and website */}
|
{/* Title and website */}
|
||||||
<Link to={`projects/${project.id}`} className={theme.content()}>
|
<div className={theme.content()}>
|
||||||
<p className={theme.title()}>{project.name}</p>
|
<p className={theme.title()}>{project.name}</p>
|
||||||
<p className={theme.description()}>
|
<p className={theme.description()}>
|
||||||
{project.deployments[0]?.domain?.name ?? 'No domain'}
|
{project.deployments[0]?.domain?.name ?? 'No domain'}
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</div>
|
||||||
{/* Icons */}
|
{/* Icons */}
|
||||||
<div className={theme.icons()}>
|
<div className={theme.icons()}>
|
||||||
{hasError && <WarningDiamondIcon className="text-elements-danger" />}
|
{hasError && <WarningDiamondIcon className="text-elements-danger" />}
|
||||||
@ -87,10 +102,7 @@ export const ProjectCard = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Wave */}
|
{/* Wave */}
|
||||||
<WavyBorder
|
<WavyBorder variant="stroke-and-fill" className={theme.wavyBorder()} />
|
||||||
variant="stroke-and-fill"
|
|
||||||
className="bg-surface-card-hovered"
|
|
||||||
/>
|
|
||||||
{/* Lower content */}
|
{/* Lower content */}
|
||||||
<div className={theme.lowerContent()}>
|
<div className={theme.lowerContent()}>
|
||||||
{/* Latest deployment */}
|
{/* Latest deployment */}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import templates from 'assets/templates';
|
import templates from 'assets/templates';
|
||||||
import { RepositoryList } from 'components/projects/create/RepositoryList';
|
import RepositoryList from 'components/projects/create/RepositoryList';
|
||||||
import ConnectAccount from 'components/projects/create/ConnectAccount';
|
import ConnectAccount from 'components/projects/create/ConnectAccount';
|
||||||
import { useOctokit } from 'context/OctokitContext';
|
import { useOctokit } from 'context/OctokitContext';
|
||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
Loading…
Reference in New Issue
Block a user