粗体
斜体
~~这是一段加了删除线的文本~~
这是一段引用,巴拉巴拉巴拉。
有序列表:
无序列表:
以下是各级标题, 最多支持6级标题
#include <stdio.h>
int main() {
printf("hello nextJs!\n");
return 0;
}
Markdown 扩展支持:
| Item | Value | | -------- | --- | | Computer | $1600 | | Phone | $12 | | Pipe | $1 |
可以指定对齐方式, 如Item列左对齐, Value列右对齐, Qty列居中对齐
| Item | Value | Qty | | :------- | ----: | :---: | | Computer | $1600 | 5 | | Phone | $12 | 12 | | Pipe | $1 | 234 |
名词 1 : 定义 1(左侧有一个可见的冒号和四个不可见的空格)
代码块 2 : 这是代码块的定义(左侧有一个可见的冒号和四个不可见的空格)
代码块(左侧有八个不可见的空格)
支持在 Markdown 语法中嵌套 Html 标签,譬如,你可以用 Html 写一个纵跨两行的表格:
提示, 如果想对图片的宽度和高度进行控制, 你也可以通过img标签, 如:
Leanote[^footnote]来创建一个脚注 [^footnote]: Leanote是一款强大的开源云笔记产品.
通过 [TOC]
在文档中插入目录。
Hexo博客和1Panel用很久了,前段时间突发奇想用React和nextjs重构博客,
因为我用的Ubuntu Server 20.04 LTS 64bit
,所以直接命令行:
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
安装好了之后去应用商店安装Nodejs运行环境
。
在1panel侧边栏点击主机->文件,找到home/ubuntu
文件夹,
{
//...
"scripts": {
// ...
"move": "cp -r _next/static _next/standalone/_next && cp -r public _next/standalone",
"run": "npm run build && npm run move && export PORT=3500 && node _next/standalone/server.js"
},
// ...
}
首先,下载必要的依赖:
npm i @next/mdx @mdx-js/loader @mdx-js/react @types/mdx
更新根目录下的next.config.mjs
:
import createMDX from '@next/mdx';
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
};
const withMDX = createMDX({
extension: /\.mdx?$/,
options: {}
})
export default withMDX(nextConfig)
在根目录创建mdx-components.tsx
文件:
import Image, { ImageProps } from 'next/image';
import type { MDXComponents } from 'mdx/types';
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
del: ({ children }) => (<del className='line-through'>{children}</del>),
h1: ({ children }) => (<h1>{children}</h1>),
img: (props) => (<Image sizes=""style={{}}{...(props as ImageProps)}/>),
...components,
}
}
再在博客根目录创建posts
文件夹,在这里创建markdown文章(记住,文章格式后缀是mdx!!!
)!
下载必要依赖:
npm i next-mdx-remote gray-matter
需要再额外下载两个插件:
npm i moment
npm i -D @iconify/react
在src/app
文件夹创建lib
文件夹,再创建一个posts.ts
文件:
import fs from "fs";
import { join } from "path";
import matter from "gray-matter";
import readingTime from 'reading-time';
const postsDir = join(process.cwd(), "posts");
type readingTime = {
text: string;
minutes: string;
time: number;
words: number;
};
type MetaData = {
title: string;
date: Date;
updated: Date;
tags: string[];
categories: string[];
cover?: string;
keywords?: string,
descr?: string;
draft?: boolean;
author?: string;
readingTime?: readingTime;
};
export function getPostBySlug(slug: string) {
const realSlug = slug.replace(/\.mdx$/, "");
const fullPath = join(postsDir, `${realSlug}.mdx`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data, content, excerpt } = matter(fileContents, { excerpt: true, });
const readTime = readingTime(content);
const meta = { ...data, readingTime: readTime } as unknown as MetaData;
return { slug: realSlug, meta, content, excerpt };
}
export function getAllPosts() {
const slugs = fs.readdirSync(postsDir);
const posts = slugs.map((slug) => getPostBySlug(slug)).filter((c) => !/\.draft$/.test(c.slug));
return posts.sort((a, b) => +b.meta.date - +a.meta.date);
}
在、src/app/posts/[slug]
文件夹下创建page.tsx
,这个页面就是具体的文章页面,就是本页面:
import { MDXRemote } from "next-mdx-remote/rsc";
import { Icon } from "@iconify/react";
import { getPostBySlug, getAllPosts } from "@/lib/posts";
import moment from "moment";
import Image from "next/image";
import Link from "next/link";
type Props = {
params: { slug: string };
searchParams: { [key: string]: string | string[] | undefined };
};
async function getPost(params: Props["params"]) {
const post = getPostBySlug(params.slug);
return { post };
}
export const dynamicParams = false;
export async function generateStaticParams() {
const posts = getAllPosts();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function Post({ params }: Props) {
const { post } = await getPost(params);
return (
<>
<div className="w-full max-w-6xl my-10 mx-auto max-768:px-4 max-768:py-4">
<div className="flex mt-5 max-768:w-full max-768:flex-col">
<div className="w-3/4 max-768:w-full">
<div className="post-container bg-white rounded-t-xl px-8 py-4 shadow-sm hover:shadow-md">
<MDXRemote source={post.content} components={{}} options={{}} />
</div>
<div className="bg-white my-0 mx-auto py-1 px-0">
<div className="w-4/5 my-0 mx-auto py-4 border-2 border-solid border-miku-green rounded-md">
<Image src={} alt="avatar1" title="avatar1" className="w-16 h-16 -mt-10 mx-auto rounded-[50%]"></Image>
<div className="w-full mt-2 mx-auto flex items-center justify-center"><Icon icon="ic:outline-article" className="mr-1 text-xl" /><div className="w-12 h-max mx-1 bg-orange-400 text-center content-center rounded-md">原创</div><div className="text-lg">{post.meta?.title}</div></div>
<div className="my-2 mx-0 flex items-center justify-center">
<div className="w-28 h-8 bg-red-400 text-lg text-center content-center rounded-xl">投币</div>
<div className=""></div>
</div>
<div className="text-center text-xs text-gray-400">本博客所有文章除特别声明外,均采用<Link href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener noreferrer" className="underline mx-1 text-slate-500">CC BY-NC-SA 4.0</Link>许可协议,转载请注明来自葱苓sama!</div>
</div>
</div>
</div>
</div>
</div>
</>
);
}
再在src/app/posts/
下创建page.tsx
,它和主页一样,用来显示文章列表:
import Image from "next/image";
import Link from "next/link";
import Aside from "@/components/aside";
import { getAllPosts } from "@/lib/posts";
import { Icon } from "@iconify/react";
import moment from "moment";
import type { Metadata } from "next";
export const metadata:Metadata = {
title: "文章 - 葱苓sama",
}
export default function Posts() {
const posts = getAllPosts();
return (
<>
<div className="w-full max-w-6xl py-[40px] px-[15px] my-0 mx-auto max-768:flex-col">
<div id="recent-post" className="w-[840px] mx-auto max-768:w-full">
{posts?.map((post, index) => (
<div id="recent-post-item" className="h-40 py-4 px-4 bg-white rounded-xl overflow-hidden flex flex-col justify-center max-600:w-full max-768:flex-col" key={index}>
<Link href={`/posts/${post.slug}`} className="text-2xl">{post.meta?.title}</Link>
<div className="text-base text-slate-400">{post.meta?.descr}</div>
<div className="w-full flex flex-wrap text-xs text-gray-600 divide-x-2 divide-solid divide-gray-200">
<time className="h-max pr-2 flex items-center before:content-['发布于'] before:mr-1"><Icon icon="clarity:date-line" className="mr-1" />{moment(post.meta?.date).format('YYYY-MM-DD')}</time>
<time className="h-max px-2 flex items-center before:content-['更新于'] before:mr-1"><Icon icon="lets-icons:date-fill" className="mr-1" />{moment(post.meta?.updated).format('YYYY-MM-DD')}</time>
<Link href={`/tags/${post.meta?.tags}`} className="h-max px-2 flex items-center"><Icon icon="mdi:tag-outline" className="mr-1 divide-x-2 divide-dashed divide-orange-600" />{post.meta?.tags}</Link>
<Link href={`/categories/${post.meta?.categories}`} className="h-max px-2 flex items-center"><Icon icon="material-symbols:category-outline" className="mr-1" />{post.meta?.categories}</Link>
<span className="h-max px-2 flex items-center after:content-['条评论']"><Icon icon="mingcute:comment-fill" className="mr-1" />114514</span>
</div>
</div>
))}
</div>
</div>
</>
)
}
a small blog station.
欢迎来到我的博客🦆