init commit
This commit is contained in:
1
packages/docusaurus-plugin-docs-info/node_modules/.bin/docusaurus
generated
vendored
Symbolic link
1
packages/docusaurus-plugin-docs-info/node_modules/.bin/docusaurus
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../node_modules/@docusaurus/core/bin/docusaurus.mjs
|
15
packages/docusaurus-plugin-docs-info/package.json
Normal file
15
packages/docusaurus-plugin-docs-info/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "docusaurus-plugin-docs-info",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.1.1",
|
||||
"dayjs": "^1.11.10"
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
import { Article } from "../..";
|
||||
import { FullVersion } from "@docusaurus/plugin-content-docs/lib/types.d.ts";
|
||||
import { DocMetadata } from "@docusaurus/plugin-content-docs";
|
||||
import { usePluginData } from "@docusaurus/useGlobalData";
|
||||
import dayjs from "dayjs";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
const ArticleList: React.FC<{
|
||||
list: Article[];
|
||||
}> = ({ list: data }) => {
|
||||
const docsData = usePluginData("docusaurus-plugin-content-docs") as {
|
||||
versions: FullVersion[];
|
||||
};
|
||||
const list: Array<Array<Article>> = [];
|
||||
const map: Map<string, DocMetadata> = new Map();
|
||||
for (let i = 0; i < docsData.versions[0].docs.length; i++) {
|
||||
// @ts-ignore
|
||||
map.set(docsData.versions[0].docs[i].path, docsData.versions[0].docs[i]);
|
||||
}
|
||||
// 一行两个
|
||||
const num = 3;
|
||||
for (let i = 0; i < data.length && i < 8; i += num) {
|
||||
list.push(data.slice(i, i + num));
|
||||
}
|
||||
// 构建与docs的连接
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
for (let j = 0; j < list[i].length; j++) {
|
||||
const val = list[i][j];
|
||||
let path = val.filename.replace(/\.(md|mdx)/, "").substring(4);
|
||||
if (
|
||||
val.filename.endsWith("index.md") ||
|
||||
val.filename.endsWith("index.mdx")
|
||||
) {
|
||||
path = path.split("/").slice(0, -1).join("/") + "/";
|
||||
}
|
||||
const doc = map.get(path);
|
||||
if (doc) {
|
||||
// @ts-ignore
|
||||
list[i][j].link = doc.path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{list.map((val, index) => (
|
||||
<div className="row" key={"row-" + index}>
|
||||
{val.map((val, index) => (
|
||||
<div className="col col--4" key={"col-" + index}>
|
||||
<div
|
||||
className="card"
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
borderColor: "var(--ifm-color-primary)",
|
||||
}}
|
||||
>
|
||||
<div className="card__header">
|
||||
<Link
|
||||
// @ts-ignore
|
||||
to={val.link}
|
||||
className="text-left"
|
||||
style={{
|
||||
display: "block",
|
||||
fontSize: "18px",
|
||||
maxWidth: "80%",
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{val.title}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
<div
|
||||
className="flex flex-row w-full items-center"
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
fontSize: "12px",
|
||||
}}
|
||||
>
|
||||
<p>{dayjs(val.create_date).format("YYYY年MM月DD日")}</p>
|
||||
<Link
|
||||
// @ts-ignore
|
||||
to={val.link}
|
||||
>
|
||||
<button className="button button--link">阅读</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArticleList;
|
@ -0,0 +1,33 @@
|
||||
import { usePluginData } from "@docusaurus/useGlobalData";
|
||||
import { Articles } from "../..";
|
||||
import ArticleList from "../ArticleList";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
function LatestDocs() {
|
||||
const data = usePluginData("docusaurus-plugin-docs-info") as Articles;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="container flex flex-col"
|
||||
style={{
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<ArticleList list={data.list} />
|
||||
<div
|
||||
className="w-full"
|
||||
style={{
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
<Link exact href="/timeline">
|
||||
<button className="button button--primary button--lg">
|
||||
查看更多
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LatestDocs;
|
168
packages/docusaurus-plugin-docs-info/src/index.ts
Normal file
168
packages/docusaurus-plugin-docs-info/src/index.ts
Normal file
@ -0,0 +1,168 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import simpleGit, { DefaultLogFields } from "simple-git";
|
||||
import matter from "gray-matter";
|
||||
import { LoadContext, Plugin } from "@docusaurus/types";
|
||||
|
||||
async function readDir(pathName: string) {
|
||||
return new Promise<string[]>((resolve) => {
|
||||
const filenames: Array<string> = [];
|
||||
fs.readdir(pathName, async (_, files) => {
|
||||
await Promise.all(
|
||||
files.map((val) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
const filename = path.join(pathName, val);
|
||||
fs.stat(filename, async (_, stats) => {
|
||||
if (stats.isFile()) {
|
||||
filenames.push(filename);
|
||||
} else {
|
||||
const result = await readDir(filename);
|
||||
filenames.push(...result);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
resolve(filenames);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export interface Article {
|
||||
filename: string;
|
||||
title: string;
|
||||
create_date?: Date;
|
||||
update_date?: Date;
|
||||
}
|
||||
|
||||
export interface Articles {
|
||||
list: Article[];
|
||||
current: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export default function (
|
||||
context: LoadContext,
|
||||
options: { debug?: boolean }
|
||||
): Plugin {
|
||||
const themePath = path.resolve(__dirname, "./theme");
|
||||
return {
|
||||
name: "docusaurus-plugin-docs-info",
|
||||
getThemePath() {
|
||||
return themePath;
|
||||
},
|
||||
async contentLoaded({ content, actions }): Promise<void> {
|
||||
const { addRoute, createData, setGlobalData } = actions;
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
if (!isProd && !options.debug) {
|
||||
setGlobalData({
|
||||
current: 1,
|
||||
list: [],
|
||||
total: 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取docs下文件
|
||||
const files = await readDir("./docs");
|
||||
const git = simpleGit();
|
||||
const articles = [];
|
||||
|
||||
await Promise.all(
|
||||
files.map((file) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
if (
|
||||
!(
|
||||
file.startsWith("_") ||
|
||||
file.endsWith(".md") ||
|
||||
file.endsWith(".mdx")
|
||||
)
|
||||
) {
|
||||
return resolve();
|
||||
}
|
||||
// 读取文件内容, 查看标题, 查看日期
|
||||
const meta = matter.read(file);
|
||||
const article: Article = {
|
||||
filename: file,
|
||||
title:
|
||||
meta.data["title"] ||
|
||||
path.basename(file).split(".").slice(0, -1).join("."),
|
||||
};
|
||||
// 读取git log文件时间
|
||||
git.log<DefaultLogFields>(
|
||||
{
|
||||
format: "%ad",
|
||||
file: file,
|
||||
},
|
||||
(_, data) => {
|
||||
if (meta.data["create_date"]) {
|
||||
article.create_date = new Date(meta.data["create_date"]);
|
||||
} else {
|
||||
article.create_date = data.all.length
|
||||
? new Date(data.all[data.all.length - 1].date)
|
||||
: new Date();
|
||||
}
|
||||
if (meta.data["update_date"]) {
|
||||
article.update_date = new Date(meta.data["update_date"]);
|
||||
} else {
|
||||
article.update_date = data.latest
|
||||
? new Date(data.latest.date)
|
||||
: new Date();
|
||||
}
|
||||
articles.push(article);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// 20篇为一页, 创建时间由新到旧
|
||||
articles.sort((a, b) => {
|
||||
return b.create_date.getTime() - a.create_date.getTime();
|
||||
});
|
||||
|
||||
const pageSize = 21;
|
||||
const latest = {
|
||||
current: 1,
|
||||
list: articles.slice(0, pageSize),
|
||||
total: articles.length,
|
||||
};
|
||||
setGlobalData(latest);
|
||||
|
||||
const pageData = await createData(
|
||||
"timeline-1.json",
|
||||
JSON.stringify(latest)
|
||||
);
|
||||
addRoute({
|
||||
path: "/timeline",
|
||||
component: "@theme/Timeline",
|
||||
modules: {
|
||||
articles: pageData,
|
||||
},
|
||||
exact: true,
|
||||
});
|
||||
|
||||
for (let i = 1; i < Math.ceil(articles.length / pageSize); i++) {
|
||||
const page = i + 1;
|
||||
const pageData = await createData(
|
||||
`timeline-${page}.json`,
|
||||
JSON.stringify({
|
||||
current: i + 1,
|
||||
list: articles.slice(i * pageSize, (i + 1) * pageSize),
|
||||
total: articles.length,
|
||||
})
|
||||
);
|
||||
addRoute({
|
||||
path: `/timeline/${page}`,
|
||||
component: "@theme/Timeline",
|
||||
modules: {
|
||||
articles: pageData,
|
||||
},
|
||||
exact: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import Layout from "@theme/Layout";
|
||||
import { Article, Articles } from "../..";
|
||||
import ArticleList from "../../components/ArticleList";
|
||||
import { Pagination } from "antd";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
export interface TimelineProps {
|
||||
articles: Articles;
|
||||
}
|
||||
|
||||
function Timeline({ articles }: TimelineProps) {
|
||||
return (
|
||||
<Layout title={"最新文章 - 第" + articles.current + "页"}>
|
||||
<div
|
||||
className="container flex flex-col px-8"
|
||||
style={{
|
||||
paddingTop: "2rem",
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<ArticleList list={articles.list} />
|
||||
<div
|
||||
className="flex flex-row"
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Pagination
|
||||
current={articles.current}
|
||||
total={articles.total}
|
||||
pageSize={20}
|
||||
showSizeChanger={false}
|
||||
itemRender={(page, type, el) => {
|
||||
if (!page) {
|
||||
return el;
|
||||
}
|
||||
if (page === 1) {
|
||||
return <Link to={"/timeline"}>1</Link>;
|
||||
}
|
||||
return <Link to={"/timeline/" + page}>{page}</Link>;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default Timeline;
|
Reference in New Issue
Block a user