summaryrefslogtreecommitdiff
path: root/src/app/(home)/_components
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/(home)/_components')
-rw-r--r--src/app/(home)/_components/call-to-action.tsx23
-rw-r--r--src/app/(home)/_components/hero.tsx98
-rw-r--r--src/app/(home)/_components/posts.tsx40
3 files changed, 161 insertions, 0 deletions
diff --git a/src/app/(home)/_components/call-to-action.tsx b/src/app/(home)/_components/call-to-action.tsx
new file mode 100644
index 0000000..b75298e
--- /dev/null
+++ b/src/app/(home)/_components/call-to-action.tsx
@@ -0,0 +1,23 @@
+import { NewsletterForm } from '@/components/newsletter-form';
+import { Section } from '@/components/section';
+import type React from 'react';
+
+export function CTA(): React.ReactElement {
+ return (
+ <Section className='relative grid gap-8 px-4 py-10 sm:grid-cols-2 md:py-14 lg:px-6 lg:py-16'>
+ <div className='max-w-xl space-y-2'>
+ <h2 className='font-semibold text-2xl md:text-3xl lg:text-4xl'>
+ Subscribe to the Newsletter
+ </h2>
+ <p className='text-muted-foreground text-sm md:text-base'>
+ Get the latest articles and updates delivered straight to your inbox.
+ No spam, unsubscribe anytime.
+ </p>
+ </div>
+
+ <div className='flex w-full items-center'>
+ <NewsletterForm />
+ </div>
+ </Section>
+ );
+}
diff --git a/src/app/(home)/_components/hero.tsx b/src/app/(home)/_components/hero.tsx
new file mode 100644
index 0000000..8ac251b
--- /dev/null
+++ b/src/app/(home)/_components/hero.tsx
@@ -0,0 +1,98 @@
+import { baseOptions, linkItems } from '@/app/layout.config';
+import { Icons } from '@/components/icons/icons';
+import { Section } from '@/components/section';
+import { buttonVariants } from '@/components/ui/button';
+import { cn } from '@/lib/utils';
+import { getLinks } from 'fumadocs-ui/layouts/shared';
+import * as motion from 'motion/react-client';
+import Image from 'next/image';
+import Link from 'next/link';
+import Balancer from 'react-wrap-balancer';
+import heroImage from '../../../../public/images/gradient-noise-purple-azure-light.png';
+
+const Hero = () => {
+ const links = getLinks(linkItems, baseOptions.githubUrl);
+ const navItems = links.filter((item) =>
+ ['nav', 'all'].includes(item.on ?? 'all'),
+ );
+
+ return (
+ <Section className='relative flex flex-col items-center justify-center gap-6 overflow-hidden bg-dashed px-4 py-16 sm:px-16 sm:py-24 md:py-32'>
+ <motion.div
+ initial={{ opacity: 0 }}
+ animate={{ opacity: 1 }}
+ transition={{
+ duration: 0.4,
+ scale: { type: 'spring', visualDuration: 0.4, bounce: 0.5 },
+ }}
+ whileInView={{ opacity: 1 }}
+ viewport={{ once: true }}
+ className='-z-10 absolute inset-0 h-full w-full'
+ >
+ <Image
+ src={heroImage}
+ alt='Hero Background'
+ height={600}
+ width={704}
+ className='pointer-events-none absolute right-0 bottom-0 h-[900px] w-[1004px] max-w-[1004px] translate-x-1/2 translate-y-1/2 select-none opacity-80 dark:opacity-100'
+ priority
+ />
+ </motion.div>
+ <div className='flex items-center justify-center space-x-2'>
+ <Icons.code className='h-6 w-6 text-primary transition-transform hover:scale-125' />
+ <span className='font-medium text-muted-foreground text-sm'>
+ Full-Stack Developer & Tech Writer
+ </span>
+ </div>
+ <h1 className='max-w-3xl text-center font-bold text-4xl leading-tight tracking-tighter sm:text-5xl md:max-w-4xl md:text-6xl lg:leading-[1.1]'>
+ <Balancer>I'm John Doe , a Full-Stack Developer.</Balancer>
+ </h1>
+ <p className='max-w-xl text-center text-muted-foreground md:max-w-2xl md:text-lg'>
+ <Balancer>
+ I write about web development, software engineering, and the latest
+ technologies. I also create fun projects and tutorials to help you
+ learn and grow as a developer.
+ </Balancer>
+ </p>
+
+ <div className='flex flex-wrap items-center justify-center gap-4'>
+ <Link
+ className={cn(
+ buttonVariants({
+ variant: 'default',
+ size: 'lg',
+ }),
+ 'group rounded-full bg-primary hover:bg-primary/90',
+ )}
+ href='/posts'
+ >
+ Browse Posts
+ <Icons.arrowUpRight className='group-hover:-rotate-12 ml-2 size-5 transition-transform' />
+ </Link>
+
+ <div className='flex items-center space-x-4'>
+ {navItems
+ .filter((item) => item.type === 'icon')
+ .map((item, i) => (
+ <Link
+ key={i.toString()}
+ href={item.url}
+ className={cn(
+ buttonVariants({
+ variant: 'ghost',
+ size: 'icon',
+ }),
+ 'rounded-full',
+ )}
+ >
+ {item.icon}
+ <span className='sr-only'>{item.text}</span>
+ </Link>
+ ))}
+ </div>
+ </div>
+ </Section>
+ );
+};
+
+export default Hero;
diff --git a/src/app/(home)/_components/posts.tsx b/src/app/(home)/_components/posts.tsx
new file mode 100644
index 0000000..8c8dc33
--- /dev/null
+++ b/src/app/(home)/_components/posts.tsx
@@ -0,0 +1,40 @@
+import { Icons } from '@/components/icons/icons';
+import { PostCard } from '@/components/posts/post-card';
+import { Section } from '@/components/section';
+import { buttonVariants } from '@/components/ui/button';
+import type { Page } from '@/lib/source';
+import Link from 'next/link';
+
+export default function Posts({ posts }: { posts: Page[] }) {
+ return (
+ <Section>
+ <div className='grid divide-y divide-dashed divide-border/70 text-left dark:divide-border'>
+ {posts.map((post) => {
+ const date = new Date(post.data.date).toDateString();
+ return (
+ <PostCard
+ title={post.data.title}
+ description={post.data.description ?? ''}
+ image={post.data.image}
+ url={post.url}
+ date={date}
+ key={post.url}
+ author={post.data.author}
+ tags={post.data.tags}
+ />
+ );
+ })}
+ <Link
+ href='/posts'
+ className={buttonVariants({
+ variant: 'default',
+ className: 'group rounded-none py-4 sm:py-8',
+ })}
+ >
+ View More
+ <Icons.arrowUpRight className='group-hover:-rotate-12 ml-2 size-5 transition-transform' />
+ </Link>
+ </div>
+ </Section>
+ );
+}