This commit is contained in:
louiscklaw
2025-02-01 20:19:28 +08:00
commit 8013ac2455
274 changed files with 26971 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
function ArrowIcon() {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.07102 11.3494L0.963068 10.2415L9.2017 1.98864H2.83807L2.85227 0.454545H11.8438V9.46023H10.2955L10.3097 3.09659L2.07102 11.3494Z"
fill="currentColor"
/>
</svg>
)
}
export default function Footer() {
return (
<footer className="mb-16">
<ul className="font-sm mt-8 flex flex-col space-x-0 space-y-2 text-neutral-600 md:flex-row md:space-x-4 md:space-y-0 dark:text-neutral-300">
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="/rss"
>
<ArrowIcon />
<p className="ml-2 h-7">rss</p>
</a>
</li>
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="https://github.com/vercel/next.js"
>
<ArrowIcon />
<p className="ml-2 h-7">github</p>
</a>
</li>
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="https://vercel.com/templates/next.js/portfolio-starter-kit"
>
<ArrowIcon />
<p className="ml-2 h-7">view source</p>
</a>
</li>
</ul>
<p className="mt-8 text-neutral-600 dark:text-neutral-300">
© {new Date().getFullYear()} MIT Licensed
</p>
</footer>
)
}

View File

@@ -0,0 +1,109 @@
import Link from 'next/link'
import Image from 'next/image'
import { MDXRemote } from 'next-mdx-remote/rsc'
import { highlight } from 'sugar-high'
import React from 'react'
function Table({ data }) {
let headers = data.headers.map((header, index) => (
<th key={index}>{header}</th>
))
let rows = data.rows.map((row, index) => (
<tr key={index}>
{row.map((cell, cellIndex) => (
<td key={cellIndex}>{cell}</td>
))}
</tr>
))
return (
<table>
<thead>
<tr>{headers}</tr>
</thead>
<tbody>{rows}</tbody>
</table>
)
}
function CustomLink(props) {
let href = props.href
if (href.startsWith('/')) {
return (
<Link href={href} {...props}>
{props.children}
</Link>
)
}
if (href.startsWith('#')) {
return <a {...props} />
}
return <a target="_blank" rel="noopener noreferrer" {...props} />
}
function RoundedImage(props) {
return <Image alt={props.alt} className="rounded-lg" {...props} />
}
function Code({ children, ...props }) {
let codeHTML = highlight(children)
return <code dangerouslySetInnerHTML={{ __html: codeHTML }} {...props} />
}
function slugify(str) {
return str
.toString()
.toLowerCase()
.trim() // Remove whitespace from both ends of a string
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/&/g, '-and-') // Replace & with 'and'
.replace(/[^\w\-]+/g, '') // Remove all non-word characters except for -
.replace(/\-\-+/g, '-') // Replace multiple - with single -
}
function createHeading(level) {
const Heading = ({ children }) => {
let slug = slugify(children)
return React.createElement(
`h${level}`,
{ id: slug },
[
React.createElement('a', {
href: `#${slug}`,
key: `link-${slug}`,
className: 'anchor',
}),
],
children
)
}
Heading.displayName = `Heading${level}`
return Heading
}
let components = {
h1: createHeading(1),
h2: createHeading(2),
h3: createHeading(3),
h4: createHeading(4),
h5: createHeading(5),
h6: createHeading(6),
Image: RoundedImage,
a: CustomLink,
code: Code,
Table,
}
export function CustomMDX(props) {
return (
<MDXRemote
{...props}
components={{ ...components, ...(props.components || {}) }}
/>
)
}

View File

@@ -0,0 +1,40 @@
import Link from 'next/link'
const navItems = {
'/': {
name: 'home',
},
'/blog': {
name: 'blog',
},
'https://vercel.com/templates/next.js/portfolio-starter-kit': {
name: 'deploy',
},
}
export function Navbar() {
return (
<aside className="-ml-[8px] mb-16 tracking-tight">
<div className="lg:sticky lg:top-20">
<nav
className="flex flex-row items-start relative px-0 pb-0 fade md:overflow-auto scroll-pr-6 md:relative"
id="nav"
>
<div className="flex flex-row space-x-0 pr-10">
{Object.entries(navItems).map(([path, { name }]) => {
return (
<Link
key={path}
href={path}
className="transition-all hover:text-neutral-800 dark:hover:text-neutral-200 flex align-middle relative py-1 px-2 m-1"
>
{name}
</Link>
)
})}
</div>
</nav>
</div>
</aside>
)
}

View File

@@ -0,0 +1,36 @@
import Link from 'next/link'
import { formatDate, getBlogPosts } from 'app/blog/utils'
export function BlogPosts() {
let allBlogs = getBlogPosts()
return (
<div>
{allBlogs
.sort((a, b) => {
if (
new Date(a.metadata.publishedAt) > new Date(b.metadata.publishedAt)
) {
return -1
}
return 1
})
.map((post) => (
<Link
key={post.slug}
className="flex flex-col space-y-1 mb-4"
href={`/blog/${post.slug}`}
>
<div className="w-full flex flex-col md:flex-row space-x-0 md:space-x-2">
<p className="text-neutral-600 dark:text-neutral-400 w-[100px] tabular-nums">
{formatDate(post.metadata.publishedAt, false)}
</p>
<p className="text-neutral-900 dark:text-neutral-100 tracking-tight">
{post.metadata.title}
</p>
</div>
</Link>
))}
</div>
)
}