feat: enhance image handling and layout adjustments

- Added image quality settings and device sizes in next.config.ts for better image optimization.
- Updated package dependencies, including cheerio and baseline-browser-mapping.
- Improved global styles for blog content images to ensure responsiveness.
- Refactored button components for consistent sizing and styling across the application.
- Enhanced blog post card layout with new variants and improved author name formatting.
- Adjusted hero section and content layout for better visual appeal and user experience.
This commit is contained in:
alirez.br
2026-06-17 21:35:35 +03:30
parent a9ee6659cc
commit ff2632f8db
47 changed files with 1050 additions and 648 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ export function BlogBlockquote({ payload }: BlogBlockquoteProps) {
{citation ? (
<footer className="mt-4 border-t border-border/60 pt-4">
<cite className="text-sm text-muted-foreground not-italic">
— {citation}
{citation}
</cite>
</footer>
) : null}
+54 -4
View File
@@ -4,12 +4,13 @@ import { ImageIcon, User } from "lucide-react";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { getFeaturedImageUrl, type WpPost } from "@/lib/wp-api";
import { formatDateShamsi } from "@/lib/format-date";
import { formatAuthorName } from "@/lib/blog-utils";
function stripHtml(html: string): string {
return html.replace(/<[^>]*>/g, "").trim();
}
type BlogPostCardVariant = "default" | "tiny";
type BlogPostCardVariant = "default" | "tiny" | "related";
export function BlogPostCard({
post,
@@ -20,9 +21,57 @@ export function BlogPostCard({
}) {
const excerpt = stripHtml(post.excerpt.rendered) || stripHtml(post.content.rendered).slice(0, 160);
const modifiedDate = post.modified ? formatDateShamsi(post.modified) : null;
const authorName = post._embedded?.author?.[0]?.name ?? null;
const authorName = formatAuthorName(post._embedded?.author?.[0]?.name);
const thumbnailUrl = getFeaturedImageUrl(post, "full");
if (variant === "related") {
return (
<Link href={`/blog/${encodeURIComponent(post.slug)}`} className="block h-full min-w-0">
<Card className="h-full overflow-hidden transition-all rounded-md duration-300 hover:shadow-md flex flex-col p-0 gap-0">
<CardContent className="p-3 sm:p-4 grid grid-cols-3 gap-3 sm:gap-4 min-w-0">
{thumbnailUrl ? (
<div className="relative rounded-md aspect-[4/3] w-full overflow-hidden bg-muted shrink-0 col-span-1 min-w-0">
<Image
src={thumbnailUrl}
alt=""
fill
className="object-cover"
quality={100}
sizes="(max-width: 640px) 33vw, (max-width: 1024px) 20vw, 200px"
/>
</div>
) : (
<div
className="relative rounded-md flex aspect-[4/3] w-full items-center justify-center overflow-hidden bg-muted shrink-0 col-span-1"
aria-hidden
>
<ImageIcon className="size-10 text-muted-foreground/50" />
</div>
)}
<div className="col-span-2 min-w-0 flex flex-col justify-center">
<h4 className="text-base font-semibold leading-snug line-clamp-3">
{post.title.rendered}
</h4>
<div className="flex flex-wrap w-full items-center gap-x-4 gap-y-1 text-sm text-muted-foreground bg-muted inline-flex p-1.5 mt-3 rounded-sm">
{authorName && (
<span className="inline-flex flex-1 items-center gap-1.5 min-w-0">
<User className="size-4 shrink-0" aria-hidden />
<span className="truncate">{authorName}</span>
</span>
)}
{modifiedDate && (
<time dateTime={post.modified} className="shrink-0">
{modifiedDate}
</time>
)}
</div>
</div>
</CardContent>
</Card>
</Link>
);
}
if (variant === "tiny") {
return (
<Link href={`/blog/${encodeURIComponent(post.slug)}`} className="block h-full">
@@ -35,7 +84,8 @@ export function BlogPostCard({
alt=""
fill
className="object-cover"
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
quality={100}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
/>
</div>
) : (
@@ -82,7 +132,7 @@ export function BlogPostCard({
className="object-cover"
quality={100}
priority
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 350px"
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
/>
</div>
) : (
-2
View File
@@ -140,7 +140,6 @@ export function BlogPostMeta({
<Button
variant="ghost"
size="icon-sm"
className="size-8 text-muted-foreground hover:text-foreground"
onClick={copyLink}
aria-label="کپی لینک"
>
@@ -160,7 +159,6 @@ export function BlogPostMeta({
<Button
variant="ghost"
size="icon-sm"
className="size-8 text-muted-foreground hover:text-foreground"
onClick={handleShare}
aria-label="اشتراک‌گذاری"
>
+1 -1
View File
@@ -20,7 +20,7 @@ export function BlogPullquote({ payload }: BlogPullquoteProps) {
{citation ? (
<footer className="mt-4">
<cite className="text-sm text-muted-foreground not-italic">
— {citation}
{citation}
</cite>
</footer>
) : null}
+17 -6
View File
@@ -11,24 +11,35 @@ export default function ContentSection() {
<div className="relative mb-6 sm:mb-0">
<div className="bg-linear-to-b aspect-76/59 relative rounded-2xl from-zinc-300 to-transparent p-px dark:from-zinc-700">
<Image
src="/assets/Echosystem.png"
className="rounded-[15px] object-cover"
alt="اکوسیستم یکپارچه فیپ"
src="/assets/main-pic/intelligent-workflow-control-center.jpg"
className="rounded-[15px] object-cover dark:hidden"
alt="مرکز کنترل گردش کار هوشمند"
width={1207}
height={929}
quality={100}
sizes="(max-width: 640px) 100vw, 50vw"
/>
<Image
src="/assets/main-pic/intelligent-workflow-control-center-dark.jpg"
className="hidden rounded-[15px] object-cover dark:block"
alt="مرکز کنترل گردش کار هوشمند"
width={1207}
height={929}
quality={100}
sizes="(max-width: 640px) 100vw, 50vw"
/>
</div>
</div>
<div className="relative space-y-4">
<p className="text-muted-foreground leading-relaxed tracking-normal">
<p className="text-muted-foreground leading-relaxed tracking-normal text-justify sm:text-start">
فیپ یک گروه متخصص است که در حوزه اینتگریشن و روش‌های نوین یکپارچه‌سازی فعالیت می‌کند.{" "}
<span className="text-accent-foreground font-bold">
<span className="text-primary font-bold">
ما با استفاده از تکنولوژی‌های پیشرفته و رویکردهای نوآورانه
</span>{" "}
به کسب‌وکارها کمک می‌کنیم تا سیستم‌های خود را به شکلی کارآمد و قابل‌اعتماد بهم متصل کنند.
</p>
<p className="text-muted-foreground leading-relaxed tracking-normal">
<p className="text-muted-foreground leading-relaxed tracking-normal text-justify sm:text-start">
ما در زمینه یکپارچه‌سازی سیستم‌ها، اتوماسیون فرآیندها، ارتباطات چندکاناله و مدیریت داده‌ها تخصص داریم. با استفاده از روش‌های نوین و ابزارهای پیشرفته، راهکارهای سفارشی برای هر کسب‌وکار طراحی و پیاده‌سازی می‌کنیم که به آن‌ها امکان می‌دهد تا از قدرت اتوماسیون و ارتباطات هوشمند بهره‌مند شوند.
</p>
+56 -34
View File
@@ -20,22 +20,29 @@ export default function Features() {
type ImageKey = "item-1" | "item-2" | "item-3" | "item-4";
const [activeItem, setActiveItem] = useState<ImageKey>("item-1");
const sectionImage = (filename: string) =>
`/assets/main-pic/4section/${encodeURIComponent(filename)}`;
const images = {
"item-1": {
image: "/assets/main-pic/4section/Systems Integration.jpg",
alt: "System integration",
image: sectionImage("Systems Integration.jpg"),
imageDark: sectionImage("Systems Integration-dark.jpg"),
alt: "یکپارچه‌سازی سیستم‌ها",
},
"item-2": {
image: "/assets/main-pic/4section/Powerful Management panels.jpg",
alt: "Management panels",
image: sectionImage("Powerful Management panels.jpg"),
imageDark: sectionImage("Powerful Management panels-dark.jpg"),
alt: "پنل‌های مدیریتی قدرتمند",
},
"item-3": {
image: "/assets/main-pic/4section/Interaction with Social Networks.jpg",
alt: "Social media integration",
image: sectionImage("Interaction with Social Networks.jpg"),
imageDark: sectionImage("Interaction with Social Networks_dark.jpg"),
alt: "تعامل با شبکه‌های اجتماعی",
},
"item-4": {
image: "/assets/main-pic/4section/Process Automation.jpg",
alt: "Process automation",
image: sectionImage("Process Automation.jpg"),
imageDark: sectionImage("Process Automation-dark.jpg"),
alt: "اتوماسیون فرآیندها",
},
};
@@ -113,33 +120,48 @@ export default function Features() {
</AccordionItem>
</Accordion>
<div className="bg-background relative flex overflow-hidden rounded-3xl border p-0 m-0">
<div className="w-15 absolute inset-0 right-0 ml-auto border-l bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_8px)]"></div>
<div className="aspect-76/59 bg-background relative w-full rounded-3xl m-0 p-0">
<AnimatePresence mode="wait">
<motion.div
key={`${activeItem}-id`}
initial={{ opacity: 0, y: 6, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 6, scale: 0.98 }}
transition={{ duration: 0.2 }}
className="size-full overflow-hidden rounded-3xl m-0 p-0"
>
<Image
src={images[activeItem].image}
className="size-full object-cover dark:mix-blend-lighten"
alt={images[activeItem].alt}
width={1207}
height={929}
/>
</motion.div>
</AnimatePresence>
<div className="relative rounded-3xl bg-linear-to-br from-primary/50 via-accent/40 to-secondary/50 p-px shadow-lg shadow-primary/10">
<div className="bg-background relative flex overflow-hidden rounded-[calc(1.5rem-1px)] m-0 p-0">
<div className="w-15 absolute inset-0 right-0 ml-auto border-l border-primary/15 bg-[repeating-linear-gradient(-45deg,color-mix(in_oklab,var(--color-primary)_25%,var(--color-border)),color-mix(in_oklab,var(--color-primary)_25%,var(--color-border))_1px,transparent_1px,transparent_8px)]"></div>
<div className="aspect-76/59 bg-background relative w-full rounded-[calc(1.5rem-1px)] m-0 p-0">
<AnimatePresence mode="wait">
<motion.div
key={`${activeItem}-id`}
initial={{ opacity: 0, y: 6, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 6, scale: 0.98 }}
transition={{ duration: 0.2 }}
className="size-full overflow-hidden rounded-[calc(1.5rem-1px)] m-0 p-0"
>
<Image
src={images[activeItem].image}
className="size-full object-cover dark:hidden"
alt={images[activeItem].alt}
width={1207}
height={929}
quality={100}
sizes="(max-width: 768px) 100vw, 50vw"
/>
<Image
src={images[activeItem].imageDark}
className="hidden size-full object-cover dark:block"
alt={images[activeItem].alt}
width={1207}
height={929}
quality={100}
sizes="(max-width: 768px) 100vw, 50vw"
/>
</motion.div>
</AnimatePresence>
</div>
<BorderBeam
duration={6}
size={200}
borderWidth={1}
colorFrom="#FCC61D"
colorTo="#01796F"
/>
</div>
<BorderBeam
duration={6}
size={200}
className="from-transparent via-yellow-700 to-transparent dark:via-white/50"
/>
</div>
</div>
</div>
+68 -61
View File
@@ -72,9 +72,11 @@ export default function HeroSection() {
<Image
src="/assets/main-pic/main-pic.jpg"
alt="background"
className="hidden size-full dark:block"
width="1150"
height="613"
className="hidden size-full object-cover dark:block"
width={1150}
height={613}
quality={100}
sizes="100vw"
/>
</AnimatedGroup>
@@ -120,7 +122,7 @@ export default function HeroSection() {
as="p"
className="mx-auto mt-8 max-w-2xl text-balance text-base md:text-lg leading-relaxed tracking-normal"
>
ما مجموعه‌ای از ابزارهای یکپارچه‌سازی، اتوماسیون و ارتباطات ارائه می‌کنیم که به شما کمک می‌کند داده‌ها، کاربران و فرآیندهای کسب‌وکارتان را از هر سیستم یا پلتفرمی — از وب‌سایت و CRM گرفته تا تلگرام و سرویس‌های سفارشی — به شکلی دقیق، سریع و قابل‌اعتماد بهم متصل کنید.
با ابزارهای یکپارچه‌سازی، اتوماسیون و ارتباطات ما، داده‌ها، کاربران و فرآیندهای کسب‌وکارتان را از هر سیستم یا پلتفرمی، از وب‌سایت و CRM تا تلگرام و سرویس‌های سفارشی، دقیق، سریع و قابل اعتماد به هم متصل کنید.
</TextEffect>
<AnimatedGroup
@@ -141,11 +143,7 @@ export default function HeroSection() {
key={1}
className="bg-foreground/10 rounded-[calc(var(--radius-xl)+0.125rem)] border p-0.5"
>
<Button
asChild
size="lg"
className="rounded-xl px-5 text-base"
>
<Button asChild size="lg">
<Link href="#link">
<span className="text-nowrap">شروع کنید</span>
</Link>
@@ -168,78 +166,87 @@ export default function HeroSection() {
...transitionVariants,
}}
>
<div className="relative mt-8 overflow-hidden px-2 sm:mt-12 md:mt-20 p-2">
<div className="ring-background bg-background relative max-w-5xl mx-auto overflow-hidden rounded-2xl border ring-1 aspect-[3/2]">
<Image
src="/assets/main-pic/Untitled-1 copy-min.jpg"
alt="یکپارچه‌سازی سیستم‌ها و شبکه دیجیتال"
fill
className="object-cover rounded-2xl inline-block my-0"
quality={100}
priority
/>
<div className="relative mt-8 overflow-visible px-2 sm:mt-12 md:mt-20 p-2">
<div className="relative max-w-4xl mx-auto flex items-center justify-center">
<div className="relative rounded-2xl overflow-hidden">
{/* Glow effect */}
<div className="absolute inset-0 rounded-2xl bg-gradient-to-r from-blue-500/20 via-purple-500/20 to-pink-500/20 blur-3xl -z-10 scale-110 animate-pulse" />
<div className="absolute inset-0 rounded-2xl bg-gradient-to-r from-blue-400/30 via-purple-400/30 to-pink-400/30 blur-2xl -z-10 scale-105" />
<div className="relative bg-background rounded-2xl border ring-1 ring-border/50 shadow-2xl shadow-blue-500/10 dark:shadow-blue-500/20">
<Image
src="/assets/main-pic/1.jpg"
alt="یکپارچه‌سازی سیستم‌ها و شبکه دیجیتال"
width={1920}
height={1280}
className="object-contain rounded-2xl w-full h-auto max-h-[600px] md:max-h-[700px] dark:hidden"
quality={100}
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 90vw, 1200px"
/>
<Image
src="/assets/main-pic/1dark.jpg"
alt="یکپارچه‌سازی سیستم‌ها و شبکه دیجیتال"
width={1920}
height={1280}
className="hidden object-contain rounded-2xl w-full h-auto max-h-[600px] md:max-h-[700px] dark:block"
quality={100}
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 90vw, 1200px"
/>
</div>
</div>
</div>
</div>
</AnimatedGroup>
</div>
</section>
<section className="bg-background pb-16 pt-16 md:pb-32">
<div className="group relative m-auto max-w-5xl px-6">
<div className="absolute inset-0 z-10 flex scale-95 items-center justify-center opacity-0 duration-500 group-hover:scale-100 group-hover:opacity-100">
<Link
href="/"
className="block text-sm duration-150 hover:text-accent transition-colors"
>
<span> اتصال به سایر سیستم ها </span>
<ChevronRight className="ml-1 inline-block size-3" />
</Link>
<div className="m-auto max-w-5xl px-6">
<div className="text-center">
<p className="text-sm font-medium text-muted-foreground">
یکپارچه با ابزارهای محبوب
</p>
<h2 className="mt-2 text-lg font-semibold md:text-xl">
اتصال به سایر سیستم‌ها
</h2>
</div>
<div className="group-hover:blur-xs mx-auto mt-12 grid max-w-4xl grid-cols-4 gap-x-12 gap-y-8 transition-all duration-500 group-hover:opacity-50 sm:gap-x-16 sm:gap-y-14">
<LogoItem
icon="logos:telegram"
alt="Telegram Logo"
size="md"
className="translate-x-1"
/>
<div className="mx-auto mt-10 flex max-w-3xl flex-wrap items-center justify-center gap-4 sm:gap-5">
<LogoItem icon="logos:telegram" alt="Telegram Logo" size="md" />
<LogoItem
icon="simple-icons:n8n"
alt="n8n Logo"
size="lg"
className="translate-x-4 "
iconClassName="text-black"
/>
<LogoItem
icon="skill-icons:wordpress"
alt="WordPress Logo"
size="md"
className="-translate-x-2"
/>
<LogoItem icon="logos:google-icon" alt="Google Logo" size="md" />
<LogoItem
icon="logos:whatsapp-icon"
alt="WhatsApp Logo"
size="md"
/>
<LogoItem
icon="logos:google-icon"
alt="Google Logo"
icon="logos:microsoft-windows-icon"
alt="Microsoft Windows Logo"
size="md"
className="translate-x-5"
/>
<div className="col-span-4 flex justify-center gap-x-12 sm:gap-x-40">
<LogoItem
icon="logos:whatsapp-icon"
alt="WhatsApp Logo"
size="md"
className="translate-x-2"
/>
<LogoItem
icon="logos:microsoft-windows-icon"
alt="Microsoft Windows Logo"
size="md"
className="translate-x-2"
/>
<LogoItem
icon="skill-icons:github-dark"
alt="github Logo"
size="md"
className="translate-x-4"
/>
</div>
<LogoItem icon="logos:github-icon" alt="GitHub Logo" size="md" />
</div>
<div className="mt-8 text-center">
<Link
href="/"
className="inline-flex items-center text-sm text-muted-foreground transition-colors hover:text-accent"
>
<span>مشاهده همه یکپارچه‌سازی‌ها</span>
<ChevronRight className="ml-1 inline-block size-3" />
</Link>
</div>
</div>
</section>
+2 -9
View File
@@ -61,10 +61,7 @@ export function LoginForm({
/>
</Field>
<Field>
<Button
type="submit"
className="w-full h-10 sm:h-11 text-sm sm:text-base"
>
<Button type="submit" size="lg" className="w-full">
ورود
</Button>
</Field>
@@ -72,11 +69,7 @@ export function LoginForm({
یا ادامه با
</FieldSeparator>
<Field className="">
<Button
variant="outline"
type="button"
className="w-full h-10 sm:h-11 text-sm sm:text-base"
>
<Button variant="outline" type="button" size="lg" className="w-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
+2 -2
View File
@@ -174,10 +174,10 @@ export default function Pricing() {
ما آماده‌ایم تا بر اساس نیازهای شما بهترین پیشنهاد را ارائه دهیم.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button asChild size="lg" className="text-base px-8 py-6">
<Button asChild size="lg">
<Link href="#chat">شروع گفتگو با تیم</Link>
</Button>
<Button asChild size="lg" variant="outline" className="text-base px-8 py-6">
<Button asChild size="lg" variant="outline">
<Link href="/about">درباره ما</Link>
</Button>
</div>
+2 -2
View File
@@ -41,11 +41,11 @@ export function ScrollToTop({ className }: { className?: string }) {
)}
>
<Button
size="icon"
size="icon-lg"
variant="outline"
onClick={scrollToTop}
aria-label="برگشت به بالا"
className="size-10 rounded-md shadow-md"
className="shadow-md"
>
<ChevronUp className="size-5" />
</Button>
+2 -4
View File
@@ -18,8 +18,7 @@ export function ThemeToggle() {
return (
<Button
variant="ghost"
size="sm"
className="size-9 rounded-lg"
size="icon"
aria-label="Toggle theme"
>
<Sun className="size-4" />
@@ -30,9 +29,8 @@ export function ThemeToggle() {
return (
<Button
variant="ghost"
size="sm"
size="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
className="size-9 rounded-lg transition-all duration-300 hover:bg-muted"
aria-label="Toggle theme"
>
<Sun className="size-4 rotate-0 scale-100 transition-all duration-300 dark:-rotate-90 dark:scale-0" />
+1 -1
View File
@@ -57,7 +57,7 @@ export const BorderBeam = ({
delay = 0,
duration = 6,
colorFrom = "#FCC61D",
colorTo = "#0046FF",
colorTo = "#01796F",
transition,
style,
reverse = false,
+12 -10
View File
@@ -5,25 +5,27 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground transition-colors",
default:
"bg-primary text-primary-foreground hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground",
destructive:
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-[#FCC61D] dark:hover:text-foreground transition-colors",
"border border-primary text-primary bg-transparent hover:bg-accent hover:text-foreground hover:border-accent dark:bg-input/30 dark:border-input dark:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground transition-colors",
"bg-secondary text-secondary-foreground hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground",
ghost:
"hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground transition-colors",
link: "text-primary underline-offset-4 hover:text-accent hover:underline dark:hover:text-[#FCC61D] transition-colors",
"hover:bg-accent hover:text-foreground dark:hover:bg-[#FCC61D] dark:hover:text-foreground",
link:
"text-primary underline-offset-4 hover:text-accent hover:underline dark:hover:text-[#FCC61D]",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
default: "h-9 px-4 text-sm has-[>svg]:px-3",
sm: "h-8 gap-1.5 px-3 text-sm has-[>svg]:px-2.5",
lg: "h-11 px-8 text-base has-[>svg]:px-6",
icon: "size-9",
"icon-sm": "size-8",
"icon-lg": "size-10",
@@ -51,7 +53,7 @@ function Button({
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
className={cn(buttonVariants({ variant, size }), className)}
{...props}
/>
)
+31 -13
View File
@@ -6,26 +6,44 @@ interface LogoItemProps {
alt: string;
size?: "sm" | "md" | "lg";
className?: string;
iconClassName?: string;
}
const sizeMap = {
sm: "h-8",
md: "h-10",
lg: "h-12",
const iconSizeMap = {
sm: "size-6",
md: "size-7",
lg: "size-8",
};
export function LogoItem({ icon, alt, size = "md", className }: LogoItemProps) {
const tileSizeMap = {
sm: "size-12",
md: "size-14",
lg: "size-16",
};
export function LogoItem({
icon,
alt,
size = "md",
className,
iconClassName,
}: LogoItemProps) {
return (
<div className={cn("flex", className)}>
<Icon
icon={icon}
<div className={cn("flex items-center justify-center", className)}>
<div
className={cn(
"mx-auto w-fit dark:invert",
sizeMap[size]
"flex items-center justify-center rounded-2xl border border-border/50 bg-white shadow-sm transition-all duration-300",
"hover:-translate-y-1 hover:shadow-md",
"dark:border-white/10 dark:bg-white/95 dark:shadow-lg dark:shadow-black/25",
tileSizeMap[size]
)}
aria-label={alt}
/>
>
<Icon
icon={icon}
className={cn("shrink-0", iconSizeMap[size], iconClassName)}
aria-label={alt}
/>
</div>
</div>
);
}