Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_ #74

Merged
merged 7 commits into from
Feb 13, 2024
Merged

_ #74

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,347 changes: 1,811 additions & 5,536 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

27 changes: 0 additions & 27 deletions src/app/(pages)/blog/[post]/_seo.tsx

This file was deleted.

64 changes: 57 additions & 7 deletions src/app/(pages)/blog/[post]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,67 @@
import { Suspense } from 'react';
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getPost } from '@/app/actions/blog';
import LoadingScreen from '../loading';
import SEO from './_seo';
import BlogSection from './_blog-section';
import { getBlogPosts, getBlogPost } from '../content';
import { pub } from '@/lib/env';
import LoadingScreen from '@/app/components/reusables/loading-screen';
import BlogSection from '@/app/components/blog/blog-section';

export default async function Blog({ params }: { params: { post: string } }) {
const post = await getPost(params.post);
type RouteParams = {
params: { post: string };
};

export const generateStaticParams = async () => {
const posts = await getBlogPosts();
return posts.map((post) => ({ post: post.filename }));
};

export async function generateMetadata({
params,
}: RouteParams): Promise<Metadata> {
const post = await getBlogPost(params.post);
if (!post) {
return {};
}
const postAttrs = post.parsedContent.attributes;
const title = postAttrs.seoTitle;
const description = postAttrs.summary;
const url = pub.SITE_URL_PROD + '/' + post.filename;

const postImageWidth = 1200;
const postImageHeight = 630;
const postImageUrl = `https://via.placeholder.com/${postImageWidth}x${postImageHeight}.png/000000/ffffff/?text=${title}`;
return {
title,
description,
openGraph: {
title,
description,
type: 'article',
url,
images: [
{
url: postImageUrl,
width: postImageWidth,
height: postImageHeight,
alt: title,
},
],
},
twitter: {
card: 'summary_large_image',
title,
description,
images: [postImageUrl],
},
};
}

export default async function Blog({ params }: RouteParams) {
const post = await getBlogPost(params.post);
if (post) {
return (
<Suspense fallback={<LoadingScreen />}>
<main className="pt-5">
<SEO post={post} />
<BlogSection post={post} />
</main>
</Suspense>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use server';
import { promises as fsPromises } from 'fs';

import { promises as fsPromises } from 'fs';
import path from 'path';
import fm from 'front-matter';
import type { MDXData, BlogData } from '@/lib/types/mdx';
import { BLOG_CONTENT_PATH } from '@/lib/constants';
import type { Maybe } from '@/lib/types/global';

function parseMDX(content: string): MDXData {
return fm(content) as MDXData;
Expand All @@ -29,18 +30,18 @@ async function readMDXFile(filePath: string): Promise<MDXData> {
} catch (error) {
// TODO: hadnle err
console.error('Error reading MDX file:', error);
throw error;
throw new Error();
}
}
async function getMDXData(dir: string): Promise<BlogData[]> {
const mdxFiles = await getMDXFiles(dir);

const blogDataPromises = mdxFiles.map(async (file) => {
const parsedContent = await readMDXFile(path.join(dir, file));
const filenameSlug: string = path.basename(file, path.extname(file));
const filename: string = path.basename(file, path.extname(file));
return {
parsedContent,
filenameSlug,
filename,
};
});

Expand All @@ -50,3 +51,10 @@ async function getMDXData(dir: string): Promise<BlogData[]> {
export async function getBlogPosts(): Promise<BlogData[]> {
return getMDXData(path.join(process.cwd(), BLOG_CONTENT_PATH));
}

export async function getBlogPost(slug: string): Promise<Maybe<BlogData>> {
// TODO: optimize
const blogs = await getBlogPosts();
const blogPost = blogs.find((p) => p?.filename === slug);
return blogPost;
}
2 changes: 1 addition & 1 deletion src/app/(pages)/blog/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import LoadingScreen from '@/app/loading';
import LoadingScreen from '@/app/components/reusables/loading-screen';
export default LoadingScreen;
3 changes: 1 addition & 2 deletions src/app/(pages)/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Suspense } from 'react';
import LoadingScreen from '@/app/components/reusables/loading-screen';
import BlogPosts from '@/app/components/blog/blog-posts';
import { getBlogPosts } from '@/app/actions/blog';
import { getBlogPosts } from './content';
import { notFound } from 'next/navigation';

export default async function BlogPage() {
const blogPosts = await getBlogPosts();

Expand Down
49 changes: 0 additions & 49 deletions src/app/actions/blog.ts

This file was deleted.

31 changes: 0 additions & 31 deletions src/app/api/blogs/route.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/app/components/blog/blog-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function BlogPostCard({ blogData }: { blogData: BlogData }) {
<li className="list-disc ml-5 dimmed-0">
{formatDate(blogData.parsedContent.attributes.firstModDate)}
</li>
<Link href={`${BLOG_URI}/${blogData.filenameSlug}`}>
<Link href={`${BLOG_URI}/${blogData.filename}`}>
<h2 className="text-2xl font-bold dimmed-4 lg:text-[2.5rem]">
{blogData.parsedContent.attributes.title}
</h2>
Expand All @@ -39,7 +39,7 @@ export default function BlogPostCard({ blogData }: { blogData: BlogData }) {
</div>
</div>
<Link
href={`${BLOG_URI}/${blogData.filenameSlug}`}
href={`${BLOG_URI}/${blogData.filename}`}
className="relative h-full overflow-hidden rounded-[2rem]"
></Link>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/blog/blog-posts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function BlogPosts({ blogPosts }: { blogPosts: BlogData[] }) {
.slice(0, visibleNum)
.map((post, index) => (
<motion.div
key={post.filenameSlug}
key={post.filename}
initial={{
opacity: 0,
y: -200, // y: index % 2 == 0 ? -200 : 200 , push for 5 wehn blogs are 20+
Expand Down
18 changes: 10 additions & 8 deletions src/app/components/nav/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ import { Button } from '@/app/components/ui/button';
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';
import useToggleDropDownMenu from '@/lib/hooks/useToggleDropDownMenue';

export default function NavBar() {
const [isOpened, setIsOpened] = useState(false);
const [isOpened, toggleMenu] = useToggleDropDownMenu({
menuId: 'nav-menue',
});

const toggleMenu = () => {
setIsOpened(!isOpened);
};
return (
<nav className="pt-3">
<nav id="nav-menue" className="pt-3">
<div className="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8 ">
<div className="relative flex h-16 items-center justify-between">
<div className="absolute inset-y-0 left-2 flex items-center sm:hidden">
<div
id="hamburger"
className="absolute inset-y-0 left-2 flex items-center sm:hidden"
>
<HamburgerButton isOpened={isOpened} onClick={toggleMenu} />
</div>
<div className="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
Expand All @@ -45,7 +47,7 @@ export function Logo() {
height={25}
src="https://avatars.githubusercontent.com/u/126174609?v=4"
className="h-8 w-auto rounded-full invisible"
alt="..."
alt="The logo"
/>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/styles/hamburger.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
stroke: white;
stroke-width: 6;
transition:
stroke-dasharray 200ms cubic-bezier(0.4, 0, 0.2, 1),
stroke-dashoffset 200ms cubic-bezier(0.4, 0, 0.2, 1);
stroke-dasharray 300ms cubic-bezier(0.4, 0, 0.2, 1),
stroke-dashoffset 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ham-line1 {
stroke-dasharray: 60 207;
Expand Down
Empty file added src/lib/declarations/aze.ts
Empty file.
39 changes: 39 additions & 0 deletions src/lib/declarations/err.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import pkg from '../../../package.json';
import { nextJS } from '../env';

abstract class BaseErr extends Error {
private readonly version = pkg.version;
readonly caughtError?: Error;

constructor(
readonly message: string,
readonly error?: Error
) {
super(message, error);
this.caughtError = error;
}

toJSON(): _SerializedErr {
return {
version: 'v' + this.version,
caughtError: this.caughtError?.name,
message: this.caughtError?.message || this.message,
stack:
nextJS.NEXT_NODE_ENV === 'production'
? 'HIDDEN'
: this.caughtError?.stack || this.stack,
cause:
JSON.stringify(this.caughtError?.cause) || JSON.stringify(this.cause),
};
}
}

type _SerializedErr = {
version: string;
caughtError?: string;
message: string;
stack?: string;
cause: string;
};

declare class Err extends BaseErr {}
35 changes: 35 additions & 0 deletions src/lib/hooks/useToggleDropDownMenue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client';

import { useState, useEffect } from 'react';
import type { MouseEvent, TouchEvent } from 'react';

const useToggleDropDownMenu = ({
menuId,
}: {
menuId: string;
}): [boolean, () => void] => {
const initialState = false;
const [isOpened, setIsOpened] = useState(initialState);

const toggleMenu: () => void = () => {
setIsOpened(!isOpened);
};

useEffect(() => {
const handleClickOutside = (e: MouseEvent | TouchEvent) => {
if (!document.getElementById(menuId)?.contains(e.target as Node)) {
setIsOpened(initialState);
}
};
// @ts-expect-error it just works, no time to set types
window.addEventListener('click', handleClickOutside);

return () => {
// @ts-expect-error it just works, no time to set types
window.removeEventListener('click', handleClickOutside);
};
}, [menuId]);

Check warning on line 31 in src/lib/hooks/useToggleDropDownMenue.ts

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'initialState'. Either include it or remove the dependency array

return [isOpened, toggleMenu];
};
export default useToggleDropDownMenu;
Loading
Loading