chore: first commit

This commit is contained in:
Daniil
2026-02-17 23:36:55 +03:00
parent 2e4820ac91
commit 674d5d735b
116 changed files with 327 additions and 150 deletions
+142
View File
@@ -0,0 +1,142 @@
"use client"
import type { IProjectCardProps } from "./ProjectCard.d"
import type { JSX } from "react"
import { Image as ImageIcon, MoreHorizontal } from "lucide-react"
import { FunctionComponent } from "react"
import cs from "classnames"
import moment from "moment"
import { Card } from "@shared/ui/Card"
import { CircularProgress } from "@shared/ui/CircularProgress"
import {
Dropdown,
DropdownContent,
DropdownItem,
DropdownTrigger,
} from "@shared/ui/Dropdown"
import styles from "./ProjectCard.module.scss"
export const ProjectCard: FunctionComponent<IProjectCardProps> = ({
project,
className,
progress = 0,
currentAction,
imageUrl,
onClick,
}): JSX.Element => {
const { name, updated_at, status } = project
const temporaryStatuses = new Set(["PROCESSING", "RENDERING", "UPLOADING"])
const isCompleted = status === "DONE"
const isProcessing = temporaryStatuses.has(status)
const isDraft = status === "DRAFT"
const isFailed = status === "FAILED"
const shouldShowProgress = isProcessing
// Helper to determine status color/class
const getStatusClass = () => {
if (isCompleted) return styles.statusGenerated
if (isProcessing) return styles.statusProcessing
if (isDraft) return styles.statusDraft
if (isFailed) return styles.statusFailed
return styles.statusDraft
}
const getStatusLabel = () => {
if (isCompleted) return "Завершено"
if (isProcessing) return "В процессе" // Or more specific state
if (isDraft) return "Черновик"
if (isFailed) return "Ошибка"
return status
}
const displayAction = currentAction || (isProcessing ? "В процессе" : "")
return (
<Card className={cs(styles.root, className)} onClick={onClick}>
<div className={styles.hero}>
{imageUrl ? (
<img src={imageUrl} alt={name} loading="lazy" />
) : (
<div className={styles.placeholder}>
<ImageIcon />
</div>
)}
<div className={styles.statusBadge}>
<div className={cs(styles.status, getStatusClass())}>
<span className={styles.statusDot} />
{getStatusLabel()}
</div>
</div>
{shouldShowProgress && (
<div className={styles.progressOverlay}>
<div className={styles.progressCircle}>
<CircularProgress
percentage={Math.min(100, Math.max(0, progress))}
color="var(--purple-500)"
bgClassName={styles.progressBg}
valueClassName={styles.progressValue}
/>
<span className={styles.percentage}>{Math.round(progress)}%</span>
</div>
{displayAction && (
<span className={styles.actionName} title={displayAction}>
{displayAction}
</span>
)}
</div>
)}
</div>
<div className={styles.content}>
<div className={styles.info}>
<div className={styles.infoHeader}>
<h3 className={styles.title} title={name}>
{name}
</h3>
<div
className={styles.menuTrigger}
onClick={(e) => e.stopPropagation()}
>
<Dropdown>
<DropdownTrigger asChild>
<button type="button" aria-label="Project actions">
<MoreHorizontal size={16} />
</button>
</DropdownTrigger>
<DropdownContent align="end">
<DropdownItem
onSelect={() => console.log("Edit", project.id)}
>
Изменить
</DropdownItem>
<DropdownItem
onSelect={() => console.log("Rename", project.id)}
>
Переименовать
</DropdownItem>
<DropdownItem
className="text-red-500"
onSelect={() => console.log("Delete", project.id)}
>
Удалить
</DropdownItem>
</DropdownContent>
</Dropdown>
</div>
</div>
<span className={styles.date}>
Создано {moment(updated_at).fromNow()}
</span>
</div>
</div>
</Card>
)
}