TorbatYar/frontend/components/ui/AppTile.tsx
Mortezakoohjani 579e0cdaf5 Link active apps on homepage and refresh landing page design.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 22:48:46 +03:30

81 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Link from "next/link";
import type { PlatformApp } from "@/lib/apps-catalog";
import { Badge } from "./Badge";
export interface AppTileProps {
app: PlatformApp;
onClick?: () => void;
variant?: "default" | "compact";
}
function AppTileContent({ app, variant = "default" }: { app: PlatformApp; variant?: "default" | "compact" }) {
const isAvailable = app.status === "available";
const isCompact = variant === "compact";
return (
<>
<div
className={`relative flex items-center justify-center rounded-[22px] bg-gradient-to-br ${app.gradient} shadow-lg shadow-black/10 transition-transform duration-300 group-hover:scale-105 group-hover:shadow-xl ${
isCompact ? "h-14 w-14 text-2xl" : "h-[72px] w-[72px] text-3xl sm:h-20 sm:w-20 sm:text-4xl"
}`}
>
<span role="img" aria-hidden>
{app.icon}
</span>
{!isAvailable ? (
<span className="absolute -bottom-1 -left-1">
<Badge variant="muted">بهزودی</Badge>
</span>
) : null}
{isAvailable ? (
<span className="absolute -bottom-1 -left-1 opacity-0 transition-opacity group-hover:opacity-100">
<Badge variant="primary">فعال</Badge>
</span>
) : null}
</div>
<div className="min-w-0 flex-1">
<p className={`truncate font-bold text-secondary ${isCompact ? "text-sm" : "text-sm sm:text-[15px]"}`}>
{app.name}
</p>
{!isCompact ? (
<p className="mt-0.5 line-clamp-2 text-xs text-gray-500">{app.description}</p>
) : null}
</div>
{isAvailable && app.href ? (
<span className="mt-auto text-xs font-medium text-primary opacity-0 transition-opacity group-hover:opacity-100">
ورود
</span>
) : null}
</>
);
}
const tileClassName =
"group flex w-full flex-col items-center gap-3 rounded-2xl border border-transparent bg-white p-3 text-center shadow-sm transition-all duration-300 hover:border-[var(--color-primary-muted)] hover:bg-[var(--color-primary-soft)] hover:shadow-md sm:p-4";
const disabledClassName =
"group flex w-full flex-col items-center gap-3 rounded-2xl border border-gray-100 bg-gray-50/60 p-3 text-center opacity-70 sm:p-4";
export function AppTile({ app, onClick, variant = "default" }: AppTileProps) {
const isAvailable = app.status === "available";
if (isAvailable && app.href && !onClick) {
return (
<Link href={app.href} className={tileClassName}>
<AppTileContent app={app} variant={variant} />
</Link>
);
}
return (
<button
type="button"
onClick={onClick}
disabled={!isAvailable && !onClick}
className={isAvailable || onClick ? tileClassName : disabledClassName}
>
<AppTileContent app={app} variant={variant} />
</button>
);
}