mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
* docs: optimize route higtlight (#4520) * docs: optimize home display (#4519) * docs: optimize home display and route highlight * docs: optimize home display * fix(alert): propagate className (#4535) * fix(alert): propagate className * chore(alert): remove className from alert theme * fix(avatar): title type in Avatar (#4529) * fix(avatar): title type in Avatar * fix(alert): apply isEmpty check on title * fix(alert): alert interface props type * refactor: remove unnecessary props types (#4530) * refactor(docs): remove string type as it is included in ReactNode * refactor: remove unnecessary types * feat(changeset): add changeset * chore: remove changeset * refactor: remove null since ReactNode unions it already * fix(input): use onPress for wrapper click focus (#4483) * fix(input): use onPress for wrapper click focus * test(input): wrapper click focus test * chore(changeset): input onPress for wrapper click focus * chore(changeset): minor wording * Refactor/rebrand (#4532) * chore: rebrand in progress * chore: update docs to use heroui * chore: components renbranded * chore: figma moved to the docs files * fix: posthog config * fix(docs): extra classname in form example (#4465) * chore: clean git * chore: make heroui private * chore: new logo * chore: node env var renamed * chore: public robots txt deleted * chore: wrangler installed * chore: wrangler renamed * chore: cloudlfare workers removed * chore: force vercel deploy * refactor: first migration and provider * refactor: rename nextui plugin * refactor: rename github site * refactor: rename CONTRIBUTING * refactor: rename package name * refactor: nextjs image hostname * refactor: mdx repo nextui-org rename frontio-ai * refactor: nextui.org rename heroui.com * refactor: add heroui to missing places * fix: heroui plugin name * fix: update docs * docs: nextui to heroui add npmrc pnpm migratation * chore: rename all packages with new org name * chore: replace frontio-ai by frontioai * chore: revert previous changes * chore: small adjustment * chore: doc updated * feat: blog * chore: avatar updated * fix: url * chore: add new ogimage * fix: ogimage command * fix: heroui name and storybook welcome page * fix: og image url * feat: favicon and icon changed --------- Co-authored-by: աӄա <wingkwong.code@gmail.com> Co-authored-by: winches <329487092@qq.com> * fix: postbuild script * chore: core package updates * ci(changesets): version packages (#4569) Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * feat: contributors added to the blog --------- Co-authored-by: winches <329487092@qq.com> Co-authored-by: աӄա <wingkwong.code@gmail.com> Co-authored-by: Peterl561 <76144929+Peterl561@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import {BlogPost} from "contentlayer2/generated";
|
|
import {Card, CardFooter, CardBody, CardHeader, Link, Avatar, Image} from "@heroui/react";
|
|
import Balancer from "react-wrap-balancer";
|
|
import {format, parseISO} from "date-fns";
|
|
import NextLink from "next/link";
|
|
import {AnimatePresence, motion} from "framer-motion";
|
|
import {usePostHog} from "posthog-js/react";
|
|
|
|
import {useIsMounted} from "@/hooks/use-is-mounted";
|
|
|
|
const BlogPostCard = (post: BlogPost) => {
|
|
const isMounted = useIsMounted();
|
|
|
|
const posthog = usePostHog();
|
|
|
|
const handlePress = () => {
|
|
posthog.capture("BlogPostCard - Selection", {
|
|
name: post.title,
|
|
action: "click",
|
|
category: "blog",
|
|
data: post.url ?? "",
|
|
});
|
|
};
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{isMounted && (
|
|
<motion.article
|
|
animate={{opacity: 1, y: 0}}
|
|
exit={{opacity: 0, y: 5}}
|
|
initial={{opacity: 0, y: 5}}
|
|
transition={{duration: 0.3}}
|
|
>
|
|
<Card
|
|
disableRipple
|
|
isBlurred
|
|
as={NextLink}
|
|
className="p-2 h-full border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
|
|
href={post.url}
|
|
isPressable={!!post.url}
|
|
onPress={handlePress}
|
|
>
|
|
<CardHeader>
|
|
<Link
|
|
as={NextLink}
|
|
className="font-semibold text-foreground"
|
|
href={post.url}
|
|
size="lg"
|
|
underline="hover"
|
|
onPress={handlePress}
|
|
>
|
|
<Balancer>{post.title}</Balancer>
|
|
</Link>
|
|
</CardHeader>
|
|
<CardBody className="pt-0 px-2 pb-1">
|
|
<Image className="mb-4" src={post.image} />
|
|
<p className="font-normal w-full text-default-600">{post.description}</p>
|
|
</CardBody>
|
|
<CardFooter className="flex justify-between items-center">
|
|
<time className="block text-small text-default-500" dateTime={post.date}>
|
|
{format(parseISO(post.date), "LLLL d, yyyy")} {post?.draft && " (Draft)"}
|
|
</time>
|
|
<Avatar size="sm" src={post.author?.avatar} />
|
|
</CardFooter>
|
|
</Card>
|
|
</motion.article>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
};
|
|
|
|
export const BlogPostList = ({posts}: {posts: BlogPost[]}) => {
|
|
return (
|
|
<div className="mt-10 grid gap-4 grid-cols-[repeat(auto-fill,minmax(300px,1fr))]">
|
|
{posts.map((post, idx) => (
|
|
<BlogPostCard key={idx} {...post} />
|
|
))}
|
|
</div>
|
|
);
|
|
};
|