-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8f8f92b
commit 17b1ec1
Showing
23 changed files
with
282 additions
and
166 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { useEffect, useState } from "react"; | ||
import { ThemeProvider } from "next-themes"; | ||
|
||
import "@/styles/globals.css"; | ||
import RootLayout from "@/ui/layouts/Default"; | ||
import type { AppProps } from "next/app"; | ||
|
||
import ErrorBoundary from "@/ui/ErrorBoundary"; | ||
|
||
export default function App({ Component, pageProps }: AppProps) { | ||
const [showing, setShowing] = useState(false); | ||
|
||
useEffect(() => { | ||
setShowing(true); | ||
}, []); | ||
|
||
if (!showing) { | ||
return null; | ||
} | ||
|
||
if (typeof window === "undefined") { | ||
return <></>; | ||
} else { | ||
return ( | ||
<RootLayout> | ||
<ThemeProvider enableSystem={true} attribute="class"> | ||
<Component {...pageProps} /> | ||
</ThemeProvider> | ||
</RootLayout> | ||
); | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// TODO: fix forced left-margin | ||
|
||
import Head from "next/head"; | ||
import Link from "next/link"; | ||
|
||
import { getCategories, getPostsData } from "@/lib/api"; | ||
import { InferGetStaticPropsType } from "next"; | ||
|
||
import Info from "@/ui/Info"; | ||
import Container from "@/ui/Container"; | ||
import { Suspense, useState, useEffect } from "react"; | ||
import { useTheme } from "next-themes"; | ||
import clsx from "clsx"; | ||
|
||
|
||
export default function HomePage({ | ||
posts, | ||
projects, | ||
}: InferGetStaticPropsType<typeof getStaticProps>) { | ||
const [mounted, setMounted] = useState(false); | ||
const { resolvedTheme, setTheme } = useTheme(); | ||
|
||
// After mounting, we have access to the theme | ||
useEffect(() => setMounted(true), []); | ||
|
||
return ( | ||
<> | ||
<Container> | ||
<div className="space-y-6"> | ||
<div className="space-y-8 text-white"> | ||
<div className="mt-12 max-w-screen-md space-y-4 dark:bg-red-200"> | ||
<Info /> | ||
</div> | ||
|
||
<div className="mt-22 max-w-screen-md space-y-4"> | ||
<h1 className="md:text-2xl font-semibold text-orange-500"> | ||
Recent Blog Posts | ||
</h1> | ||
<Suspense fallback={null}> | ||
<div className="flex flex-col divide-y-[1px] divide-zinc-700"> | ||
{posts.map((post: any) => ( | ||
<Link | ||
key={post.slug} | ||
href={{ | ||
pathname: "/blog/[slug]", | ||
query: { slug: post.slug }, | ||
}} | ||
className="flex flex-row py-4 justify-between hover:text-orange-500" | ||
> | ||
<div>{post.title}</div> | ||
<div className="text-zinc-500"> | ||
{post.categories.map((category: any) => category.name)} | ||
</div> | ||
</Link> | ||
))} | ||
{!posts.length && <div>No Blog Posts found.</div>} | ||
</div> | ||
</Suspense> | ||
</div> | ||
|
||
<div className="mt-22 max-w-screen-md space-y-4"> | ||
<h1 className="md:text-2xl font-semibold text-orange-500"> | ||
Featured Projects | ||
</h1> | ||
<Suspense fallback={null}> | ||
<div className="flex-col space-y-2"> | ||
{projects.map((project: any) => ( | ||
<Link | ||
href={`/`} | ||
key={project} | ||
className="block space-y-1.5 rounded-lg border border-white/10 px-4 py-3 hover:border-white/20 bg-zinc-800" | ||
> | ||
<div>{project.name}</div> | ||
<div className="line-clamp-3 text-sm text-zinc-400"> | ||
{project.slug} | ||
</div> | ||
</Link> | ||
))} | ||
{!projects.length && <div>No Project found.</div>} | ||
</div> | ||
</Suspense> | ||
</div> | ||
</div> | ||
</div> | ||
</Container> | ||
</> | ||
); | ||
} | ||
|
||
export async function getStaticProps() { | ||
const butterToken = process.env.NEXT_PUBLIC_BUTTER_CMS_API_KEY; | ||
|
||
if (butterToken) { | ||
try { | ||
const blogPosts = (await getPostsData()).posts; | ||
const projects = await getCategories(); | ||
|
||
return { props: { posts: blogPosts, projects } }; | ||
} catch (e) { | ||
// throw new Error("Could not get posts!"); | ||
} | ||
} | ||
|
||
return { props: { posts: [], projects: [] } }; | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import Head from "next/head"; | ||
import { useRouter } from "next/router"; | ||
import { useState, useEffect } from "react"; | ||
import { useTheme } from "next-themes"; | ||
// import NextLink from "next/link"; | ||
// import clsx from "clsx"; | ||
|
||
type ContainerProps = { | ||
children: React.ReactNode; | ||
customMeta?: { | ||
date?: any; | ||
}; | ||
}; | ||
|
||
export default function Container({ children, customMeta }: ContainerProps) { | ||
const [mounted, setMounted] = useState(false); | ||
const { resolvedTheme, setTheme } = useTheme(); | ||
|
||
// After mounting, we have access to the theme | ||
useEffect(() => setMounted(true), []); | ||
|
||
const router = useRouter(); | ||
const meta = { | ||
title: "Mohi Khashan | Front-end Engineer.", | ||
description: `Front-end developer, JavaScript enthusiast, and course creator.`, | ||
image: "https://leerob.io/static/images/lee-banner.png", | ||
type: "website", | ||
...customMeta, | ||
}; | ||
|
||
return ( | ||
<div className="bg-gray-50 dark:bg-gray-900"> | ||
<Head> | ||
<title>{meta.title}</title> | ||
<meta name="robots" content="follow, index" /> | ||
<meta content={meta.description} name="description" /> | ||
<meta property="og:url" content={`https://leerob.io${router.asPath}`} /> | ||
<link rel="canonical" href={`https://leerob.io${router.asPath}`} /> | ||
<meta property="og:type" content={meta.type} /> | ||
<meta property="og:site_name" content="Mohi Khashan" /> | ||
<meta property="og:description" content={meta.description} /> | ||
<meta property="og:title" content={meta.title} /> | ||
<meta property="og:image" content={meta.image} /> | ||
<meta name="twitter:card" content="summary_large_image" /> | ||
<meta name="twitter:site" content="@leeerob" /> | ||
<meta name="twitter:title" content={meta.title} /> | ||
<meta name="twitter:description" content={meta.description} /> | ||
<meta name="twitter:image" content={meta.image} /> | ||
{meta.date && ( | ||
<meta property="article:published_time" content={meta.date} /> | ||
)} | ||
</Head> | ||
<button | ||
aria-label="Toggle Dark Mode" | ||
type="button" | ||
className="w-9 h-9 bg-gray-200 rounded-lg dark:bg-gray-600 flex items-center justify-center hover:ring-2 ring-gray-300 transition-all" | ||
onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")} | ||
> | ||
{mounted && ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
viewBox="0 0 24 24" | ||
fill="none" | ||
stroke="currentColor" | ||
className="w-5 h-5 text-gray-800 dark:text-gray-200" | ||
> | ||
{resolvedTheme === "dark" ? ( | ||
<path | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
strokeWidth={2} | ||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" | ||
/> | ||
) : ( | ||
<path | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
strokeWidth={2} | ||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" | ||
/> | ||
)} | ||
</svg> | ||
)} | ||
</button> | ||
<main | ||
id="skip" | ||
className="flex flex-col justify-center px-8 bg-gray-50 dark:bg-gray-900" | ||
> | ||
{children} | ||
</main> | ||
</div> | ||
); | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.