Nextjs笔记Nextjs笔记
Nextjs笔记

markdown语法测试

排版

粗体

斜体

~~这是一段加了删除线的文本~~

这是一段引用,巴拉巴拉巴拉。

有序列表:

  1. 支持Vim
  2. 支持Emacs

无序列表:

  • 项目1
  • 项目2

图片与链接

图片测试

这是去往我的主页的链接

标题

以下是各级标题, 最多支持6级标题

h1

h2

h3

h4

h5
h6

代码

#include <stdio.h>
int main() {
  printf("hello nextJs!\n");
  return 0;
}

Markdown 扩展

Markdown 扩展支持:

  • 表格
  • 定义型列表
  • Html 标签
  • 脚注
  • 目录
  • 时序图与流程图
  • MathJax 公式

表格

| 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 : 这是代码块的定义(左侧有一个可见的冒号和四个不可见的空格)

代码块(左侧有八个不可见的空格)

html标签

支持在 Markdown 语法中嵌套 Html 标签,譬如,你可以用 Html 写一个纵跨两行的表格:

提示, 如果想对图片的宽度和高度进行控制, 你也可以通过img标签, 如:

脚注

Leanote[^footnote]来创建一个脚注 [^footnote]: Leanote是一款强大的开源云笔记产品.

目录

通过 [TOC] 在文档中插入目录。

时序图与流程图

MathJax 公式

记一次1Panel的nodejs运行环境部署博客

说在前面

Hexo博客和1Panel用很久了,前段时间突发奇想用Reactnextjs重构博客,

安装1Panel

因为我用的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文件夹,

package.json

{
  //...
  "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"
  },
  // ...
}

标签挂件

note

这是一个 note 的 default 标签。
这是一个 note 的 success 标签。
这是一个 note 的 warn 标签。

button

mdx

Todo

首先,下载必要的依赖:

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!!!)!

next-mdx-remote

下载必要依赖:

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>
      </>
    )
}

扩展

avatar1
原创
Nextjs笔记
本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议,转载请注明来自葱苓sama!
正在加载评论...
Welcome!!
avatar
葱苓sama

a small blog station.

公告

欢迎来到我的博客🦆

最新评论
    标签
    • C-practice
    • Ccpp
    • C-study
    • Nextjs笔记
    • 随笔