laconic-deploy/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx
icld 134d4ad316 Squashed commit of the following:
commit ea08482596e10f27536af2d32040b476a18085e0
Author: icld <ian@icld.io>
Date:   Tue Feb 25 07:06:03 2025 -0800

    refactor: update WalletContext import and enhance layout components
2025-02-28 09:07:15 -08:00

106 lines
2.8 KiB
TypeScript

import { Tag } from '@/components/shared/Tag';
import { useToast } from '@/components/shared/Toast';
import { Card } from '@/components/ui/card';
import { cn } from '@/utils/classnames';
import { GitBranch } from 'lucide-react';
import React, { ComponentPropsWithoutRef, useCallback } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
export interface TemplateDetail {
id: string;
name: string;
icon: string;
repoFullName?: string;
isComingSoon?: boolean;
}
export interface TemplateCardProps extends ComponentPropsWithoutRef<'div'> {
template: TemplateDetail;
isGitAuth: boolean;
}
export const TemplateCard: React.FC<TemplateCardProps> = ({
template,
isGitAuth,
className,
...props
}: TemplateCardProps) => {
const { toast, dismiss } = useToast();
const navigate = useNavigate();
const { orgSlug } = useParams();
const handleClick = useCallback(() => {
if (template?.isComingSoon) {
return toast({
id: 'coming-soon',
title: 'This template is coming soon',
variant: 'info',
onDismiss: dismiss,
});
}
if (isGitAuth) {
return navigate(
`/${orgSlug}/projects/create/template?templateId=${template.id}`,
);
}
return toast({
id: 'connect-git-account',
title: 'Connect Git account to start with a template',
variant: 'error',
onDismiss: dismiss,
});
}, [orgSlug, dismiss, isGitAuth, navigate, template, toast]);
// Extract short name for icon (e.g., "PWA" from "Progressive Web App")
const shortName = template.name
.split(' ')
.map((word) => word[0])
.join('')
.slice(0, 3);
return (
<Card
className={cn(
'flex flex-col gap-2 p-4 bg-[#121212] hover:bg-[#1a1a1a] rounded-xl cursor-pointer transition-all',
template?.isComingSoon && 'cursor-default opacity-70',
className,
)}
onClick={handleClick}
{...props}
>
<div className="flex items-start gap-3">
{/* Icon */}
<div className="flex-shrink-0 w-10 h-10 flex items-center justify-center rounded-md bg-[#1E1E1E] text-white font-medium text-xs">
{shortName}
</div>
<div className="flex flex-col gap-1">
{/* Name */}
<p className="text-sm font-medium text-white">{template.name}</p>
{/* Repo name */}
{template.repoFullName && (
<div className="flex items-center gap-1 text-[#8A8A8E] text-xs">
<GitBranch size={12} />
<span>{template.repoFullName}</span>
</div>
)}
</div>
</div>
{template?.isComingSoon && (
<Tag
size="xs"
type="neutral"
leftIcon={<GitBranch size={12} />}
className="self-start mt-1"
>
Soon
</Tag>
)}
</Card>
);
};