diff --git a/blog/alert.tsx b/blog/alert.tsx
new file mode 100644
index 0000000..9b863cb
--- /dev/null
+++ b/blog/alert.tsx
@@ -0,0 +1,40 @@
+import Container from "@/components/blog/container";
+import {cn} from "@/lib/utils";
+
+type Props = {
+ preview?: boolean;
+};
+
+const Alert = ({ preview }: Props) => {
+ return (
+
+
+
+ {preview ? (
+ <>
+ This page is a preview.{" "}
+
+ Click here
+ {" "}
+ to exit preview mode.
+ >
+ ) : (
+ <>
+ Thunder Network
+ >
+ )}
+
+
+
+ );
+};
+
+export default Alert;
diff --git a/blog/avatar.tsx b/blog/avatar.tsx
new file mode 100644
index 0000000..9c2ea4d
--- /dev/null
+++ b/blog/avatar.tsx
@@ -0,0 +1,15 @@
+type Props = {
+ name: string;
+ picture: string;
+};
+
+const Avatar = ({ name, picture }: Props) => {
+ return (
+
+
+
{name}
+
+ );
+};
+
+export default Avatar;
diff --git a/blog/container.tsx b/blog/container.tsx
new file mode 100644
index 0000000..17458eb
--- /dev/null
+++ b/blog/container.tsx
@@ -0,0 +1,9 @@
+type Props = {
+ children?: React.ReactNode;
+};
+
+const Container = ({ children }: Props) => {
+ return {children}
;
+};
+
+export default Container;
diff --git a/blog/cover-image.tsx b/blog/cover-image.tsx
new file mode 100644
index 0000000..44a5f78
--- /dev/null
+++ b/blog/cover-image.tsx
@@ -0,0 +1,36 @@
+import Link from "next/link";
+import Image from "next/image";
+import {cn} from "@/lib/utils";
+
+type Props = {
+ title: string;
+ src: string;
+ slug?: string;
+};
+
+const CoverImage = ({ title, src, slug }: Props) => {
+ const image = (
+
+ );
+ return (
+
+ {slug ? (
+
+ {image}
+
+ ) : (
+ image
+ )}
+
+ );
+};
+
+export default CoverImage;
diff --git a/blog/date-formatter.tsx b/blog/date-formatter.tsx
new file mode 100644
index 0000000..b092f5e
--- /dev/null
+++ b/blog/date-formatter.tsx
@@ -0,0 +1,12 @@
+import { parseISO, format } from "date-fns";
+
+type Props = {
+ dateString: string;
+};
+
+const DateFormatter = ({ dateString }: Props) => {
+ const date = parseISO(dateString);
+ return ;
+};
+
+export default DateFormatter;
diff --git a/blog/footer.tsx b/blog/footer.tsx
new file mode 100644
index 0000000..a432f95
--- /dev/null
+++ b/blog/footer.tsx
@@ -0,0 +1,32 @@
+import Container from "@/components/blog/container";
+import { EXAMPLE_PATH } from "@/lib/blog/constants";
+
+export function Footer() {
+ return (
+
+ );
+}
+
+export default Footer;
diff --git a/blog/header.tsx b/blog/header.tsx
new file mode 100644
index 0000000..0aa782e
--- /dev/null
+++ b/blog/header.tsx
@@ -0,0 +1,14 @@
+import Link from "next/link";
+
+const Header = () => {
+ return (
+
+
+ Blog
+
+ .
+
+ );
+};
+
+export default Header;
diff --git a/blog/hero-post.tsx b/blog/hero-post.tsx
new file mode 100644
index 0000000..5b63291
--- /dev/null
+++ b/blog/hero-post.tsx
@@ -0,0 +1,47 @@
+import Avatar from "@/components/blog/avatar";
+import CoverImage from "@/components/blog/cover-image";
+import { type Author } from "@/interfaces/author";
+import Link from "next/link";
+import DateFormatter from "./date-formatter";
+
+type Props = {
+ title: string;
+ coverImage: string;
+ date: string;
+ excerpt: string;
+ author: Author;
+ slug: string;
+};
+
+export function HeroPost({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}: Props) {
+ return (
+
+
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/blog/intro.tsx b/blog/intro.tsx
new file mode 100644
index 0000000..8934f65
--- /dev/null
+++ b/blog/intro.tsx
@@ -0,0 +1,13 @@
+
+export function Intro() {
+ return (
+
+
+ Blog.
+
+
+ Thunder Network
+
+
+ );
+}
diff --git a/blog/more-stories.tsx b/blog/more-stories.tsx
new file mode 100644
index 0000000..17191da
--- /dev/null
+++ b/blog/more-stories.tsx
@@ -0,0 +1,29 @@
+import { Post } from "@/interfaces/post";
+import { PostPreview } from "./post-preview";
+
+type Props = {
+ posts: Post[];
+};
+
+export function MoreStories({ posts }: Props) {
+ return (
+
+
+ More Stories
+
+
+ {posts.map((post) => (
+
+ ))}
+
+
+ );
+}
diff --git a/blog/post-header.tsx b/blog/post-header.tsx
new file mode 100644
index 0000000..1c7ad91
--- /dev/null
+++ b/blog/post-header.tsx
@@ -0,0 +1,34 @@
+import Avatar from "./avatar";
+import CoverImage from "./cover-image";
+import DateFormatter from "./date-formatter";
+import { PostTitle } from "@/components/blog/post-title";
+import { type Author } from "@/interfaces/author";
+
+type Props = {
+ title: string;
+ coverImage: string;
+ date: string;
+ author: Author;
+};
+
+export function PostHeader({ title, coverImage, date, author }: Props) {
+ return (
+ <>
+ {title}
+
+
+
+
+
+ >
+ );
+}
diff --git a/blog/post-preview.tsx b/blog/post-preview.tsx
new file mode 100644
index 0000000..07415d1
--- /dev/null
+++ b/blog/post-preview.tsx
@@ -0,0 +1,41 @@
+import { type Author } from "@/interfaces/author";
+import Link from "next/link";
+import Avatar from "./avatar";
+import CoverImage from "./cover-image";
+import DateFormatter from "./date-formatter";
+
+type Props = {
+ title: string;
+ coverImage: string;
+ date: string;
+ excerpt: string;
+ author: Author;
+ slug: string;
+};
+
+export function PostPreview({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}: Props) {
+ return (
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+
{excerpt}
+
+
+ );
+}
diff --git a/blog/post-title.tsx b/blog/post-title.tsx
new file mode 100644
index 0000000..5d2dc0b
--- /dev/null
+++ b/blog/post-title.tsx
@@ -0,0 +1,13 @@
+import { ReactNode } from "react";
+
+type Props = {
+ children?: ReactNode;
+};
+
+export function PostTitle({ children }: Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/blog/section-separator.tsx b/blog/section-separator.tsx
new file mode 100644
index 0000000..62412c0
--- /dev/null
+++ b/blog/section-separator.tsx
@@ -0,0 +1,3 @@
+export function SectionSeparator() {
+ return
;
+}
diff --git a/blog/switch.module.css b/blog/switch.module.css
new file mode 100644
index 0000000..9ab3692
--- /dev/null
+++ b/blog/switch.module.css
@@ -0,0 +1,56 @@
+.switch {
+ all: unset;
+ position: absolute;
+ right: 20px;
+ top: 70px;
+ display: inline-block;
+ color: currentColor;
+ border-radius: 50%;
+ border: 1px dashed currentColor;
+ cursor: pointer;
+ --size: 24px;
+ height: var(--size);
+ width: var(--size);
+ transition: all 0.3s ease-in-out 0s !important;
+}
+
+[data-mode="system"] .switch::after {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ font-weight: 600;
+ font-size: calc(var(--size) / 2);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ content: "A";
+}
+
+[data-mode="light"] .switch {
+ box-shadow: 0 0 50px 10px yellow;
+ background-color: yellow;
+ border: 1px solid orangered;
+}
+
+[data-mode="dark"] .switch {
+ box-shadow: calc(var(--size) / 4) calc(var(--size) / -4) calc(var(--size) / 8)
+ inset #fff;
+ border: none;
+ background: transparent;
+ animation: n linear 0.5s;
+}
+
+@keyframes n {
+ 40% {
+ transform: rotate(-15deg);
+ }
+ 80% {
+ transform: rotate(10deg);
+ }
+ 0%,
+ 100% {
+ transform: rotate(0deg);
+ }
+}