Add new card components for blog and product sections

Introduced four new Astro components: CardBlog, CardBlogRecent, CardSmall and CardWide, designed for displaying blog entries and products. These components have been equipped with asset imports, content collection types, and interactive prefetch links for better user experience and performance.
This commit is contained in:
Emil Gulamov 2024-02-17 08:16:16 +04:00
parent 771a3aacd9
commit bfc01cc16d
4 changed files with 186 additions and 0 deletions

View file

@ -0,0 +1,52 @@
---
import AvatarBlog from "../avatars/AvatarBlog.astro";
import {Image} from "astro:assets";
import {formatDate} from "../../../utils";
import type {CollectionEntry} from "astro:content";
const {blogEntry} = Astro.props;
interface Props {
blogEntry: CollectionEntry<"blog">;
}
---
<a class="group relative block rounded-xl outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none transition duration-500"
href={`/blog/${blogEntry.slug}/`} data-astro-prefetch>
<div class="flex-shrink-0 relative rounded-xl overflow-hidden w-full h-[350px] before:absolute before:inset-x-0 before:size-full before:bg-gradient-to-t before:from-neutral-900/[.7] before:z-[1]">
<Image class="size-full absolute top-0 start-0 object-cover group-hover:scale-110 transition duration-500"
src={blogEntry.data.cardImage} alt={blogEntry.data.cardImageAlt} draggable={"false"} format={"avif"}/>
</div>
<div class="absolute top-0 inset-x-0 z-10">
<div class="p-4 flex flex-col h-full sm:p-6">
<div class="flex items-center">
<AvatarBlog blogEntry={blogEntry}/>
<div class="ms-2.5 sm:ms-4">
<h4 class="font-bold text-neutral-50">
{blogEntry.data.author}
</h4>
<p class="text-xs text-neutral-50/[.8]">
{formatDate(blogEntry.data.pubDate)}
</p>
</div>
</div>
</div>
</div>
<div class="absolute bottom-0 inset-x-0 z-10">
<div class="flex flex-col h-full p-4 sm:p-6">
<h3 class="text-lg sm:text-3xl font-bold text-neutral-50 group-hover:text-neutral-50/[.8]">
{blogEntry.data.title}
</h3>
<p class="mt-2 text-neutral-50/[.8]">
{blogEntry.data.description}
</p>
</div>
</div>
</a>

View file

@ -0,0 +1,50 @@
---
import { Image } from "astro:assets";
import type { CollectionEntry } from "astro:content";
import AvatarBlogLarge from "../avatars/AvatarBlogLarge.astro";
import PrimaryCTA from "../buttons/PrimaryCTA.astro";
const { blogEntry } = Astro.props;
interface Props {
blogEntry: CollectionEntry<"blog">;
}
---
<div class="grid sm:grid-cols-2 sm:items-center gap-8">
<div class="sm:order-2">
<div class="relative pt-[50%] sm:pt-[100%] rounded-lg">
<Image class="size-full absolute top-0 start-0 object-cover rounded-xl" src={blogEntry.data.cardImage} alt={blogEntry.data.cardImageAlt} draggable={"false"} format={"avif"}/>
</div>
</div>
<div class="sm:order-1">
<h2 class="text-2xl font-bold md:text-3xl lg:text-4xl lg:leading-tight xl:text-5xl xl:leading-tight text-neutral-800 dark:text-neutral-200 tracking-tight">
<a class="hover:text-[#fa5a15] dark:text-neutral-300 dark:hover:text-neutral-50 transition duration-300 focus-visible:ring outline-none dark:ring-zinc-200 ring-zinc-500 dark:focus:outline-none " href={`/blog/${blogEntry.slug}/`}>
{blogEntry.data.description}
</a>
</h2>
<div class="mt-6 sm:mt-10 flex items-center">
<AvatarBlogLarge blogEntry={blogEntry}/>
<div class="ms-3 sm:ms-4">
<p class="sm:mb-1 font-bold text-neutral-800 dark:text-neutral-200">
{blogEntry.data.author}
</p>
<p class="text-xs text-neutral-500">
{blogEntry.data.role}
</p>
</div>
</div>
<div class="mt-5">
<PrimaryCTA url={`/blog/${blogEntry.slug}/`} title="Read More" data-astro-prefetch/>
</div>
</div>
</div>

View file

@ -0,0 +1,42 @@
---
import { Image } from "astro:assets";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
interface Props {
product: CollectionEntry<"products">;
}
const imageClass =
"absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
const AnchorSVG = `
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
</svg>`;
---
<a
href={"/products/" + product.slug}
data-astro-prefetch
class="group relative flex h-48 items-end overflow-hidden rounded-xl shadow-lg outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:h-80"
>
<Image
src={product.data.main.imgCard}
alt={product.data.main.imgAlt}
draggable={"false"}
class={imageClass}
format={"avif"}
/>
<div
class="pointer-events-none absolute inset-0 bg-gradient-to-t from-neutral-800 via-transparent to-transparent opacity-50"
>
</div>
<span
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} />
</span>
</a>

View file

@ -0,0 +1,42 @@
---
import { Image } from "astro:assets";
import type { CollectionEntry } from "astro:content";
const { product } = Astro.props;
interface Props {
product: CollectionEntry<"products">;
}
const imageClass =
"absolute inset-0 h-full w-full object-cover object-center transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110";
const AnchorSVG = `
<svg fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="ml-0.5 w-3 h-3 md:w-4 md:h-4 inline pb-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25" />
</svg>`;
---
<a
href={"/products/" + product.slug}
data-astro-prefetch
class="group relative flex h-48 items-end overflow-hidden rounded-lg shadow-xl outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:col-span-2 md:h-80"
>
<Image
src={product.data.main.imgCard}
alt={product.data.main.imgAlt}
draggable={"false"}
class={imageClass}
format={"avif"}
/>
<div
class="pointer-events-none absolute inset-0 bg-gradient-to-t from-neutral-800 via-transparent to-transparent opacity-50"
>
</div>
<span
class="relative mb-3 ml-4 inline-block text-sm font-bold text-neutral-50 transition duration-[600ms] ease-[cubic-bezier(0.45,0,0.55,1)] group-hover:scale-110 md:ml-5 md:text-lg"
>{product.data.main.subTitle} <Fragment set:html={AnchorSVG} /></span
>
</a>