Skip to content

Commit

Permalink
Some dynamic animations (#73)
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
ashgw authored Feb 12, 2024
2 parents 057e780 + 1b7e28e commit 9e1defe
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 80 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"react-syntax-highlighter": "^15.5.0",
"react-use": "^17.5.0",
"sass": "^1.69.7",
"sharp": "^0.33.1",
"sharp": "^0.33.2",
"sonner": "^1.3.1",
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions src/app/(pages)/blog/[post]/_blog-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import StyledMDX from '@/app/components/mdx/styled-mdx';
import { Heading1 as H1 } from '@/app/components/reusables/headers';
import { formatDate, isSameMonthAndYear } from '@/lib/funcs/dates';
import { MediumSection } from '@/app/components/reusables/sections';
import BackUpTop from '@/app/components/reusables/back-up-top';
import type { BlogData } from '@/lib/types/mdx';
import { Badge } from '@/app/components/ui/badge';

export default function BlogSection({ post }: { post: BlogData }) {
return (
<MediumSection>
<H1 id={post.parsedContent.attributes.title}>
{post.parsedContent.attributes.title}
</H1>
<div className="flex justify-between items-center mb-8 text-sm sm:max-w-[450px] md:max-w-[550px] lg:max-w-[650px] xl:max-w-[750px] ">
<p className="text-sm dimmed-0">
{formatDate(post.parsedContent.attributes.firstModDate)}
</p>
<div>
{isSameMonthAndYear(post.parsedContent.attributes.firstModDate) ? (
// TODO: replace with views
<div className="average-transition opacity-0 hover:opacity-100">
<Badge variant={'outlineUpdated'}>Recent</Badge>
</div>
) : (
<div className="average-transition opacity-0 hover:opacity-100">
<Badge variant={'outlineArchive'}>Archive</Badge>
</div>
)}
</div>
</div>
<article className="text-wrap">
<StyledMDX source={post.parsedContent.body}></StyledMDX>
</article>
<BackUpTop />
</MediumSection>
);
}
27 changes: 27 additions & 0 deletions src/app/(pages)/blog/[post]/_seo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { BlogData } from '@/lib/types/mdx';
import { BLOG_URI } from '@/lib/constants';
import { pub } from '@/lib/env';

export default function SEO({ post }: { post: BlogData }) {
return (
<script
type="application/ld+json"
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.parsedContent.attributes.title,
datePublished: post.parsedContent.attributes.firstModDate,
dateModified: post.parsedContent.attributes.lastModDate,
description: post.parsedContent.attributes.seoTitle,
url: pub.SITE_URL_PROD + BLOG_URI + `/${post.filenameSlug}`,
author: {
'@type': 'Person',
name: 'ashgw',
},
}),
}}
/>
);
}
63 changes: 6 additions & 57 deletions src/app/(pages)/blog/[post]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,18 @@
import { Suspense } from 'react';
import LoadingScreen from '@/app/components/reusables/loading-screen';
import StyledMDX from '@/app/components/mdx/styled-mdx';
import { Heading1 as H1 } from '@/app/components/reusables/headers';
import { formatDate, isSameMonthAndYear } from '@/lib/funcs/dates';
import { MediumSection } from '@/app/components/reusables/sections';
import BackUpTop from '@/app/components/reusables/back-up-top';
import { notFound } from 'next/navigation';
import { pub } from '@/lib/env';
import { Badge } from '@/app/components/ui/badge';
import { getPost } from '@/app/actions/blog';
import { BLOG_URI } from '@/lib/constants';
import LoadingScreen from '../loading';
import SEO from './_seo';
import BlogSection from './_blog-section';

export default async function Blog({ params }: { params: { post: string } }) {
const post = await getPost(params.post);
if (post !== undefined) {
if (post) {
return (
<Suspense fallback={<LoadingScreen />}>
<main className="pt-5">
<script
type="application/ld+json"
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.parsedContent.attributes.title,
datePublished: post.parsedContent.attributes.firstModDate,
dateModified: post.parsedContent.attributes.lastModDate,
description: post.parsedContent.attributes.seoTitle,
url: pub.SITE_URL_PROD + BLOG_URI + `/${post.filenameSlug}`,
author: {
'@type': 'Person',
name: 'ashgw',
},
}),
}}
/>
<MediumSection>
<H1 id={post.parsedContent.attributes.title}>
{post.parsedContent.attributes.title}
</H1>
<div className="flex justify-between items-center mb-8 text-sm sm:max-w-[450px] md:max-w-[550px] lg:max-w-[650px] xl:max-w-[750px] ">
<p className="text-sm dimmed-0">
{formatDate(post.parsedContent.attributes.firstModDate)}
</p>
<div>
{isSameMonthAndYear(
post.parsedContent.attributes.firstModDate
) ? (
// TODO: replace with views
<div className="average-transition opacity-0 hover:opacity-100">
<Badge variant={'outlineUpdated'}>Recent</Badge>
</div>
) : (
<div className="average-transition opacity-0 hover:opacity-100">
<Badge variant={'outlineArchive'}>Archive</Badge>
</div>
)}
</div>
</div>
<article className="text-wrap">
<StyledMDX source={post.parsedContent.body}></StyledMDX>
</article>
<BackUpTop />
</MediumSection>
<SEO post={post} />
<BlogSection post={post} />
</main>
</Suspense>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/(pages)/y/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const FadeInView: React.FC = () => {
observer.unobserve(target.current);

Check warning on line 27 in src/app/(pages)/y/page.tsx

View workflow job for this annotation

GitHub Actions / lint

The ref value 'target.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'target.current' to a variable inside the effect, and use that variable in the cleanup function
}
};
});
}, []);

Check warning on line 30 in src/app/(pages)/y/page.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'isVisible'. Either include it or remove the dependency array. You can also do a functional update 'setIsVisible(i => ...)' if you only need 'isVisible' in the 'setIsVisible' call

return (
<div className="flex items-center justify-center">
Expand Down
11 changes: 6 additions & 5 deletions src/app/actions/blog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { pub, nextJS } from '@/lib/env';
import type { BlogData } from '@/lib/types/mdx';
import { BLOG_API_URI } from '@/lib/constants';
import type { Maybe } from '@/lib/types/global';
import { Status } from '@/lib/constants';

const SITE_URL =
nextJS.NEXT_NODE_ENV == 'production' ? pub.SITE_URL_PROD : pub.SITE_URL_DEV;
Expand All @@ -14,7 +15,7 @@ export async function getPost(slug: string): Promise<Maybe<BlogData>> {
cache: 'no-store',
});

if (response.status == 200) {
if (response.status == Status.OK) {
const result = (await response.json()) as { data: BlogData[] };
const blogPost = result.data.find((p) => p?.filenameSlug === slug);
return blogPost;
Expand All @@ -23,26 +24,26 @@ export async function getPost(slug: string): Promise<Maybe<BlogData>> {
return;
}
} catch (error) {
console.error('Error fetching data:', error);
console.error('Fix your schema', error);
return;
}
}

export async function getBlogPosts(): Promise<Maybe<BlogData[]>> {
try {
const response = await fetch(SITE_URL + BLOG_API_URI, {
cache: 'no-store',
cache: 'no-store', // somehow Next bugs on caches
});

if (response.status == 200) {
if (response.status == Status.OK) {
const result = (await response.json()) as { data: BlogData[] };
return result.data;
} else {
console.error('Error fetching data:', response.status);
return;
}
} catch (error) {
console.error('Error fetching data:', error);
console.error('Fix your schema', error);
return;
}
}
14 changes: 11 additions & 3 deletions src/app/api/blogs/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@ import { NextResponse } from 'next/server';
import { getBlogPosts } from '@/app/api/blogs/content';
import type { BlogData } from '@/lib/types/mdx';
import type { AsyncResponse } from '@/lib/types/global';
import { Status } from '@/lib/constants';

export async function GET(): AsyncResponse<BlogData[]> {
try {
const data: BlogData[] = await getBlogPosts();
return NextResponse.json(
{ data },
{
status: 200,
status: Status.OK,
}
);
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({ error: 'schema fumbled' }, { status: 400 });
// TODO: validate query params
return NextResponse.json(
{ error: 'fix yo shit G' },
{ status: Status.BAD_REQUEST }
);
} else {
return NextResponse.json({ error: 'no blogs exist G' }, { status: 400 });
return NextResponse.json(
{ error: 'no blogs exist G' },
{ status: Status.NOT_FOUND }
);
}
}
}
9 changes: 6 additions & 3 deletions src/app/components/blog/blog-posts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,21 @@ export default function BlogPosts({ blogPosts }: { blogPosts: BlogData[] }) {
return 1;
})
.slice(0, visibleNum)
.map((post) => (
.map((post, index) => (
<motion.div
key={post.filenameSlug}
initial={{
opacity: 0,
y: -70,
y: -200, // y: index % 2 == 0 ? -200 : 200 , push for 5 wehn blogs are 20+
}}
animate={{
opacity: 1,
y: 0,
}}
transition={{}}
transition={{
duration: 0.4,
delay: index * 0.1,
}}
>
<BlogPostCard blogData={post}></BlogPostCard>
</motion.div>
Expand Down
26 changes: 20 additions & 6 deletions src/app/components/nav/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Link from 'next/link';
import Image from 'next/image';
import HamburgerButton from '@/app/components/nav/hamburger';
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';

export default function NavBar() {
const [isOpened, setIsOpened] = useState(false);
Expand All @@ -30,10 +31,8 @@ export default function NavBar() {
<RightNav />
</div>
</div>
<div
className={`mx-2 sm:hidden translate-all duration-200 ease-in-out ${isOpened ? 'scale-100' : 'scale-0'}`}
>
{isOpened ? <DropDownNav /> : null}
<div className="mx-2 sm:hidden">
<AnimatePresence>{isOpened && <DropDownNav />}</AnimatePresence>
</div>
</nav>
);
Expand Down Expand Up @@ -89,7 +88,22 @@ export function RightNav() {

export function DropDownNav() {
return (
<div className="space-y-3 px-2 pb-3 pt-2">
<motion.div
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
transition={{
duration: 0.3,
ease: 'easeInOut',
}}
exit={{
opacity: 0,
}}
className="absolute rounded-3xl z-50 backdrop-blur-md w-full space-y-3 px-5 pb-3 pt-2"
>
<div className="average-transition hover:average-translate rounded-3xl slower-transition shadow hover:shadow-[0px_4px_88px_0px_var(--deeper-purple)] border border-white/10">
<Link
href="/blog"
Expand All @@ -112,6 +126,6 @@ export function DropDownNav() {
Contact
</Button>
</div>
</div>
</motion.div>
);
}
18 changes: 16 additions & 2 deletions src/app/components/protos/hero-section.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
/* eslint-disable */
'use client';
import { Button } from '../ui/button';
import { motion } from 'framer-motion';
import { TextContent } from '../reusables/content';
export default function HeroSection() {
return (
<section className="w-full py-12 md:py-24 lg:py-32 xl:py-48">
<motion.section
initial={{
opacity: 0,
}}
whileInView={{
opacity: 1,
}}
transition={{
duration: 0.3,
ease: 'easeInOut',
}}
className="w-full py-12 md:py-24 lg:py-32 xl:py-48"
>
<div className="container px-4 md:px-6">
<div className="flex flex-col items-center space-y-4 text-center">
<div className="space-y-2">
Expand All @@ -21,6 +35,6 @@ export default function HeroSection() {
</div>
</div>
</div>
</section>
</motion.section>
);
}
2 changes: 1 addition & 1 deletion src/app/components/reusables/sections.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function MediumSection({ children }: { children: React.ReactNode }) {
return (
<section className="dimmed-5 mx-auto container sm:max-w-xl md:max-w-2xl lg:max-w-3xl xl:max-w-4xl">
<section className="mx-auto container sm:max-w-xl md:max-w-2xl lg:max-w-3xl xl:max-w-4xl">
{children}
</section>
);
Expand Down
5 changes: 5 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export const BLOG_CONTENT_PATH = '/public/blogs';
export const BLOG_URI = '/blog';
export const BLOG_API_URI = '/api/blogs';
export const Status = {
OK: 200,
BAD_REQUEST: 400,
NOT_FOUND: 404,
};

0 comments on commit 9e1defe

Please sign in to comment.