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:
parent
771a3aacd9
commit
bfc01cc16d
4 changed files with 186 additions and 0 deletions
52
src/components/ui/cards/CardBlog.astro
Normal file
52
src/components/ui/cards/CardBlog.astro
Normal 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>
|
50
src/components/ui/cards/CardBlogRecent.astro
Normal file
50
src/components/ui/cards/CardBlogRecent.astro
Normal 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>
|
42
src/components/ui/cards/CardSmall.astro
Normal file
42
src/components/ui/cards/CardSmall.astro
Normal 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>
|
42
src/components/ui/cards/CardWide.astro
Normal file
42
src/components/ui/cards/CardWide.astro
Normal 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>
|
Loading…
Add table
Reference in a new issue