feat: 基础文章编辑功能

This commit is contained in:
2026-07-06 14:20:21 +08:00
parent e67829562d
commit 12e521891a
13 changed files with 1966 additions and 2175 deletions

View File

@@ -2,7 +2,6 @@
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import solidJs from '@astrojs/solid-js'; import solidJs from '@astrojs/solid-js';
import node from '@astrojs/node'; import node from '@astrojs/node';
import tailwindcss from "@tailwindcss/vite";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
@@ -13,6 +12,6 @@ export default defineConfig({
mode: 'standalone' mode: 'standalone'
}), }),
vite: { vite: {
plugins: [tailwindcss()], plugins: [],
}, },
}); });

View File

@@ -10,16 +10,16 @@
"deploy": "./scripts/deploy.sh" "deploy": "./scripts/deploy.sh"
}, },
"dependencies": { "dependencies": {
"@astrojs/node": "^9.5.1", "@astrojs/node": "10.0.5",
"@astrojs/solid-js": "^5.1.3", "@astrojs/solid-js": "^5.1.3",
"@tailwindcss/vite": "^4.3.2", "astro": "^7.0.6",
"astro": "^5.15.8", "dayjs": "^1.11.21",
"github-markdown-css": "^5.9.0", "github-markdown-css": "^5.9.0",
"jsdom": "^29.1.1", "jsdom": "^29.1.1",
"ky": "^2.0.2", "ky": "^2.0.2",
"shiki": "^4.3.0", "modern-normalize": "^3.0.1",
"solid-js": "^1.9.10", "shiki": "^4.3.1",
"tailwindcss": "^4.3.2" "solid-js": "^1.9.14"
}, },
"volta": { "volta": {
"node": "22.21.1" "node": "22.21.1"

3916
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
<footer> <footer>
<div class="content"> <div class="content">
<a href="https://beian.miit.gov.cn/#/Integrated/index"> <a target="_blank" href="https://beian.miit.gov.cn/#/Integrated/index">
备案号鄂ICP备2023000060号-2 备案号鄂ICP备2023000060号-2
</a> </a>
</div> </div>

View File

@@ -8,7 +8,7 @@ import { metadata } from "../consts";
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 99999; z-index: 99999;
box-shadow: rgba(17, 17, 26, 0.1) 0px 1px 0px; box-shadow: rgba(17, 17, 26, 0.1) 0 1px 0;
flex-shrink: 0; flex-shrink: 0;
background: #fff; background: #fff;
} }
@@ -25,7 +25,6 @@ import { metadata } from "../consts";
.main-nav h1 { .main-nav h1 {
user-select: none; user-select: none;
font-size: 30px;
cursor: pointer; cursor: pointer;
font-size: 24px; font-size: 24px;
} }
@@ -38,7 +37,6 @@ import { metadata } from "../consts";
align-items: center; align-items: center;
} }
/* element: menu-item */
.main-nav .menu-item a { .main-nav .menu-item a {
text-decoration: none; text-decoration: none;
} }
@@ -52,11 +50,11 @@ import { metadata } from "../consts";
<h1> <h1>
<a href="/">{metadata.siteTitle}</a> <a href="/">{metadata.siteTitle}</a>
</h1> </h1>
<ul class="menu"> <!--<ul class="menu">-->
<li class="menu-item"><a href="/">首页</a></li> <!-- <li class="menu-item"><a href="/">首页</a></li>-->
<li class="menu-item"><a href="/">文章</a></li> <!-- <li class="menu-item"><a href="/">文章</a></li>-->
<li class="menu-item"><a href="/">分类</a></li> <!-- <li class="menu-item"><a href="/">分类</a></li>-->
<li class="menu-item"><a href="/">关于</a></li> <!-- <li class="menu-item"><a href="/">关于</a></li>-->
</ul> <!--</ul>-->
</nav> </nav>
</header> </header>

View File

@@ -1,5 +1,5 @@
--- ---
import "@/styles/base.css"; import "@/styles/global.css";
import BaseHeader from "@/components/BaseHeader.astro"; import BaseHeader from "@/components/BaseHeader.astro";
import BaseFooter from "@/components/BaseFooter.astro"; import BaseFooter from "@/components/BaseFooter.astro";
@@ -28,25 +28,3 @@ const { siteTitle } = metadata;
<BaseFooter /> <BaseFooter />
</body> </body>
</html> </html>
<style>
html,
body {
width: 100%;
height: 100%;
}
body {
display: flex;
flex-direction: column;
background: #fafafa;
}
main {
flex: 1;
max-width: var(--layout-width);
width: 100%;
margin: 0 auto;
padding: 32px;
}
</style>

5
src/lib/format.ts Normal file
View File

@@ -0,0 +1,5 @@
import dayjs from 'dayjs';
export const formatDatetime = (date: string,format = 'YYYY-MM-DD HH:mm') => {
return dayjs(date).format(format);
};

View File

@@ -3,7 +3,36 @@ import {createHighlighter} from 'shiki'
const highlighter = await createHighlighter({ const highlighter = await createHighlighter({
themes: ['github-dark-dimmed'], themes: ['github-dark-dimmed'],
langs: ['javascript', 'typescript', 'css', 'tsx', 'less', 'scss', 'text'], langs: [
"bash",
"json",
"yaml",
"xml",
"html",
"css",
"scss",
"javascript",
"typescript",
"jsx",
"tsx",
"vue",
"markdown",
"sql",
"graphql",
"python",
"java",
"go",
"rust",
"c",
"cpp",
"csharp",
"php",
"ruby",
"kotlin",
"swift",
"dockerfile",
"nginx"
]
}) })
const resolveLang = (lang) => { const resolveLang = (lang) => {

View File

@@ -2,7 +2,9 @@
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import {http} from "@/lib/request.ts"; import {http} from "@/lib/request.ts";
import {highlightHtmlWithJsdom} from "@/lib/highlight.js"; import {highlightHtmlWithJsdom} from "@/lib/highlight.js";
import 'github-markdown-css/github-markdown-light.css'; import "github-markdown-css/github-markdown-light.css"
import "@/styles/github-markdown.css"
import {formatDatetime} from "@/lib/format.ts";
const {slug} = Astro.params; const {slug} = Astro.params;
@@ -12,30 +14,69 @@ interface Post {
slug: string; slug: string;
cover: string; cover: string;
published_at: string; published_at: string;
content_html: string; content: string;
} }
const {data} = await http.get<ApiResponse<Post>>(`post/${slug}`); const {data} = await http.get<ApiResponse<Post>>(`post/${slug}`);
const content = await highlightHtmlWithJsdom(data.content_html) const content = await highlightHtmlWithJsdom(data.content)
--- ---
<Layout> <Layout>
<h1>{data.title}</h1> <h1 class="post-title">{data.title}</h1>
<div>{data.published_at}</div>
<div class="post markdown-body" set:html={content}>
<div class="published-at">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="lucide lucide-calendar-days-icon lucide-calendar-days">
<path d="M8 2v4"/>
<path d="M16 2v4"/>
<rect width="18" height="18" x="3" y="4" rx="2"/>
<path d="M3 10h18"/>
<path d="M8 14h.01"/>
<path d="M12 14h.01"/>
<path d="M16 14h.01"/>
<path d="M8 18h.01"/>
<path d="M12 18h.01"/>
<path d="M16 18h.01"/>
</svg>
{formatDatetime(data.published_at)}
</div> </div>
<div class="post markdown-body" set:html={content}></div>
</Layout> </Layout>
<style> <style>
.post-title{
margin-block-start: 0;
margin-block-end: 24px;
}
@media (max-width: 768px) {
.post-title {
font-size: 24px;
}
}
.published-at{
display: flex;
align-items: center;
gap: 8px;
color: #6b7280;
font-size: 16px;
margin-bottom: 24px;
}
.published-at svg{
width: 18px;
height: 18px;
}
.post { .post {
background: #fff; background: #fff;
border-radius: 12px; border-radius: 12px;
overflow: auto; overflow: auto;
padding: 16px; padding: 24px;
box-shadow: rgba(149, 157, 165, 0.2) 0px 2px 14px -4px; box-shadow: rgba(149, 157, 165, 0.2) 0 2px 14px -4px;
} }
</style> </style>

View File

@@ -1,6 +0,0 @@
@import "tailwindcss";
:root {
--layout-width: 1200px;
}

4
src/styles/css-reset.css Normal file
View File

@@ -0,0 +1,4 @@
a {
color: inherit;
text-decoration: none;
}

View File

@@ -0,0 +1,12 @@
.markdown-body pre code{
font-size: 1.1em;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
border-bottom: none ;
}

27
src/styles/global.css Normal file
View File

@@ -0,0 +1,27 @@
@import "modern-normalize";
@import "css-reset.css";
:root {
--layout-width: 980px;
}
html,
body {
width: 100%;
height: 100%;
font-size: 16px;
}
body {
display: flex;
flex-direction: column;
background: #fafafa;
}
main {
max-width: var(--layout-width);
flex: 1;
width: 100%;
margin: 0 auto;
padding: 32px;
}