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} +
{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 = ( + {`Cover + ); + 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} + +

+
+ +
+
+
+

{excerpt}

+ +
+
+
+ ); +} 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); + } +}