Finished up the project cards
This commit is contained in:
@@ -9,7 +9,7 @@ import { useForm, type SubmitHandler } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import Button from "./Button";
|
||||
import { Divider } from "./Divider";
|
||||
import { WithScroll } from "./SidePanel";
|
||||
import { WithScroll } from "./WithScroll";
|
||||
import { TextInput, MultilineTextInput } from "./TextInput";
|
||||
import type { z } from "zod";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Children } from "@utils/types/props";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
FiMoreVertical,
|
||||
@@ -9,26 +8,11 @@ import {
|
||||
} from "react-icons/fi";
|
||||
import { Button } from "@components/Button";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import * as Dialog from "@radix-ui/react-dialog";
|
||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||
import { cx } from "class-variance-authority";
|
||||
import { TextInput, MultilineTextInput } from "@components/TextInput";
|
||||
import { Divider } from "@components/Divider";
|
||||
import { ImageInput } from "@components/ImageInput";
|
||||
import { api } from "@utils/api";
|
||||
import { getRootContainer } from "@utils/constants/htmlTools";
|
||||
import toast from "react-hot-toast";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { proposalSchema } from "@utils/constants/schema/project";
|
||||
import type { z } from "zod";
|
||||
import type { SubmitHandler } from "react-hook-form";
|
||||
import { signOut } from "next-auth/react";
|
||||
import { navItems } from "@utils/constants/sidepanel";
|
||||
import { NewProposalPopup } from "./NewProposalPopup";
|
||||
|
||||
type ProposalForm = z.infer<typeof proposalSchema>;
|
||||
|
||||
export const SidePanel: React.FC = () => {
|
||||
return (
|
||||
<div id="side-panel" className="hidden md:block">
|
||||
@@ -123,25 +107,3 @@ const MoreMenu: React.FC = () => {
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithScroll: React.FC<Children & { height: string }> = ({
|
||||
height,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<ScrollArea.Root
|
||||
type="auto"
|
||||
className={`h-${height} w-full overflow-hidden`}
|
||||
>
|
||||
<ScrollArea.Viewport className="h-full w-full">
|
||||
{children}
|
||||
</ScrollArea.Viewport>
|
||||
<ScrollArea.Scrollbar
|
||||
className="flex touch-none select-none rounded-full bg-bg-600 p-0.5 transition-colors duration-150 ease-out hover:bg-bg-700 data-[orientation=horizontal]:h-2.5 data-[orientation=vertical]:w-2.5 data-[orientation=horizontal]:flex-col"
|
||||
orientation="vertical"
|
||||
>
|
||||
<ScrollArea.Thumb className="relative flex-1 rounded-full bg-fg-700 before:absolute before:left-1/2 before:top-1/2 before:h-full before:min-h-[44px] before:w-full before:min-w-[44px] before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] hover:bg-fg" />
|
||||
</ScrollArea.Scrollbar>
|
||||
</ScrollArea.Root>
|
||||
);
|
||||
};
|
||||
|
||||
24
src/components/WithScroll.tsx
Normal file
24
src/components/WithScroll.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||
import type { Children } from "@utils/types/props";
|
||||
|
||||
export const WithScroll: React.FC<Children & { height: string }> = ({
|
||||
height,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<ScrollArea.Root
|
||||
type="auto"
|
||||
className={`h-${height} w-full overflow-hidden`}
|
||||
>
|
||||
<ScrollArea.Viewport className="h-full w-full">
|
||||
{children}
|
||||
</ScrollArea.Viewport>
|
||||
<ScrollArea.Scrollbar
|
||||
className="flex touch-none select-none rounded-full bg-bg-600 p-0.5 transition-colors duration-150 ease-out hover:bg-bg-700 data-[orientation=horizontal]:h-2.5 data-[orientation=vertical]:w-2.5 data-[orientation=horizontal]:flex-col"
|
||||
orientation="vertical"
|
||||
>
|
||||
<ScrollArea.Thumb className="relative flex-1 rounded-full bg-fg-700 before:absolute before:left-1/2 before:top-1/2 before:h-full before:min-h-[44px] before:w-full before:min-w-[44px] before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] hover:bg-fg" />
|
||||
</ScrollArea.Scrollbar>
|
||||
</ScrollArea.Root>
|
||||
);
|
||||
};
|
||||
@@ -9,8 +9,7 @@ import * as Tooltip from "@radix-ui/react-tooltip";
|
||||
import { getRootContainer } from "@utils/constants/htmlTools";
|
||||
import { NewProposalPopup } from "@components/NewProposalPopup";
|
||||
import Link from "next/link";
|
||||
import { Herr_Von_Muellerhoff } from "@next/font/google";
|
||||
import { WithScroll } from "@components/SidePanel";
|
||||
import { WithScroll } from "@components/WithScroll";
|
||||
|
||||
// === Styles =================================================================
|
||||
|
||||
@@ -42,9 +41,12 @@ type ProjectCardContainerProps = Children &
|
||||
VariantProps<typeof container>;
|
||||
|
||||
type ProjectCardProps = Component & {
|
||||
project: Omit<Project, "authorId"> & {
|
||||
members: User[];
|
||||
};
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
state: ProjectLifecycle;
|
||||
createdAt: Date;
|
||||
bannerImageUrl: string | null;
|
||||
};
|
||||
|
||||
type NewProjectCardProps = Component & { onSubmit?: () => void };
|
||||
@@ -58,14 +60,19 @@ const ProjectCardContainer: React.FC<ProjectCardContainerProps> = ({
|
||||
}) => <Tag className={container({ activity: activity })}>{children}</Tag>;
|
||||
|
||||
export const ProjectCard: React.FC<ProjectCardProps> = ({
|
||||
project,
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
state,
|
||||
component,
|
||||
createdAt,
|
||||
bannerImageUrl,
|
||||
}) => {
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
|
||||
return (
|
||||
<ProjectCardContainer activity="interactive" component={component}>
|
||||
<Link href={`/projects/${project.id}`} className="h-full w-full">
|
||||
<Link href={`/projects/${id}`} className="h-full w-full">
|
||||
<div
|
||||
className="flex h-full w-full flex-col"
|
||||
onMouseEnter={() => setShowMore(true)}
|
||||
@@ -83,28 +90,26 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({
|
||||
fill
|
||||
className="object-cover object-top"
|
||||
src={
|
||||
project.bannerImageUrl ??
|
||||
`https://picsum.photos/seed/${project.id}/300/400.webp`
|
||||
bannerImageUrl ??
|
||||
`https://picsum.photos/seed/${id}/300/400.webp`
|
||||
}
|
||||
alt={project.title}
|
||||
alt={title}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4 my-4 flex flex-grow flex-col justify-between gap-y-2 overflow-hidden overflow-ellipsis transition-all">
|
||||
<label className="block overflow-x-clip overflow-ellipsis whitespace-nowrap text-left font-bold text-r-xl">
|
||||
{project.title}
|
||||
{title}
|
||||
</label>
|
||||
{showMore && (
|
||||
<WithScroll height="full">
|
||||
<p className="mr-3 max-h-full flex-grow">
|
||||
{project.description}
|
||||
</p>
|
||||
<p className="mr-3 max-h-full flex-grow">{description}</p>
|
||||
</WithScroll>
|
||||
)}
|
||||
<div className="flex flex-row items-center gap-x-3">
|
||||
<ProjectLifecycleIndicator state={project.state} />
|
||||
<ProjectLifecycleIndicator state={state} />
|
||||
<p className="overflow-ellipsis">
|
||||
{/* TODO: Change to time last updated */}
|
||||
Created {formatDate(project.createdAt)}
|
||||
Created {formatDate(createdAt)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,9 +17,7 @@ const Discover: NextPage<
|
||||
{isLoading ? (
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
))
|
||||
data?.map((project) => <ProjectCard key={project.id} {...project} />)
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
);
|
||||
|
||||
@@ -15,9 +15,7 @@ const Discover: NextPage<
|
||||
{isLoading ? (
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
))
|
||||
data?.map((project) => <ProjectCard key={project.id} {...project} />)
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
);
|
||||
|
||||
@@ -17,9 +17,7 @@ const Discover: NextPage<
|
||||
{isLoading ? (
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
))
|
||||
data?.map((project) => <ProjectCard key={project.id} {...project} />)
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
);
|
||||
|
||||
@@ -17,9 +17,7 @@ const Discover: NextPage<
|
||||
{isLoading ? (
|
||||
<p>Loading ...</p>
|
||||
) : (
|
||||
data?.map((project) => (
|
||||
<ProjectCard key={project.id} project={project} />
|
||||
))
|
||||
data?.map((project) => <ProjectCard key={project.id} {...project} />)
|
||||
)}
|
||||
</DiscoverLayout>
|
||||
);
|
||||
|
||||
@@ -87,7 +87,7 @@ const Projects: NextPage = () => {
|
||||
{isLoading || isFetching
|
||||
? Array(5).fill(<LoadingProjectCard component="li" />)
|
||||
: sortedProjects.map((p) => (
|
||||
<ProjectCard key={p.id} project={p} component="li" />
|
||||
<ProjectCard key={p.id} {...p} component="li" />
|
||||
))}
|
||||
</ul>
|
||||
</MainLayout>
|
||||
|
||||
Reference in New Issue
Block a user