hexo-sitemap-html 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +55 -155
- package/lib/templates.js +58 -0
- package/package.json +6 -2
- package/.gitattributes +0 -2
- package/.github/workflows/npm-publish.yml +0 -33
- package/docs/en-US/README.md +0 -133
- package/docs/zh-CN/README.md +0 -128
package/index.js
CHANGED
|
@@ -3,186 +3,86 @@
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const fs = require('hexo-fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const getTemplate = require('./lib/templates'); // 引用模板
|
|
6
7
|
|
|
7
|
-
// 默认配置
|
|
8
8
|
const DEFAULT_CONFIG = {
|
|
9
9
|
path: 'sitemap.html',
|
|
10
|
-
enable: {
|
|
11
|
-
categories: true,
|
|
12
|
-
posts: true,
|
|
13
|
-
pages: true
|
|
14
|
-
},
|
|
10
|
+
enable: { categories: true, posts: true, pages: true },
|
|
15
11
|
exclude: [],
|
|
16
|
-
layout: '
|
|
12
|
+
layout: 'minimal', // 默认改用简约风
|
|
17
13
|
nofollow: false
|
|
18
14
|
};
|
|
19
15
|
|
|
20
|
-
const LAYOUT_STYLES = {
|
|
21
|
-
simple: `
|
|
22
|
-
<style>
|
|
23
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
24
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 900px; margin: 0 auto; padding: 2rem; color: #333; line-height: 1.6; }
|
|
25
|
-
h1 { text-align: center; margin-bottom: 2rem; color: #2c3e50; }
|
|
26
|
-
.section { margin-bottom: 3rem; }
|
|
27
|
-
h2 { border-bottom: 2px solid #eee; padding-bottom: 0.5rem; margin-bottom: 1rem; color: #34495e; }
|
|
28
|
-
.list { list-style: none; }
|
|
29
|
-
.list-item { padding: 0.5rem 0; border-bottom: 1px dashed #eee; display: flex; justify-content: space-between; }
|
|
30
|
-
.list-item a { color: #3498db; text-decoration: none; }
|
|
31
|
-
.list-item a:hover { color: #2980b9; text-decoration: underline; }
|
|
32
|
-
.meta { color: #95a5a6; font-size: 0.9em; }
|
|
33
|
-
</style>
|
|
34
|
-
`,
|
|
35
|
-
modern: `
|
|
36
|
-
<style>
|
|
37
|
-
:root { --primary: #6366f1; --bg: #f8fafc; --card: #ffffff; --text: #1e293b; --text-light: #64748b; }
|
|
38
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
39
|
-
body { font-family: "Inter", system-ui, sans-serif; background: var(--bg); color: var(--text); padding: 3rem 1rem; line-height: 1.5; }
|
|
40
|
-
.container { max-width: 1000px; margin: 0 auto; }
|
|
41
|
-
header { text-align: center; margin-bottom: 4rem; }
|
|
42
|
-
h1 { font-size: 2.5rem; font-weight: 800; color: var(--text); margin-bottom: 1rem; }
|
|
43
|
-
.section { margin-bottom: 4rem; }
|
|
44
|
-
h2 { font-size: 1.5rem; margin-bottom: 1.5rem; display: flex; align-items: center; gap: 0.5rem; }
|
|
45
|
-
h2::before { content: ''; display: inline-block; width: 4px; height: 1.5rem; background: var(--primary); border-radius: 4px; }
|
|
46
|
-
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.25rem; }
|
|
47
|
-
.card { background: var(--card); padding: 1.25rem; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); transition: all 0.2s; border: 1px solid #e2e8f0; text-decoration: none; display: block; }
|
|
48
|
-
.card:hover { transform: translateY(-2px); box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); border-color: var(--primary); }
|
|
49
|
-
.card-title { display: block; font-weight: 600; color: var(--text); margin-bottom: 0.5rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
50
|
-
.card-meta { font-size: 0.875rem; color: var(--text-light); }
|
|
51
|
-
@media (max-width: 640px) { .grid { grid-template-columns: 1fr; } }
|
|
52
|
-
</style>
|
|
53
|
-
`
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
function formatDate(date) {
|
|
57
|
-
if (!date) return 'No Date';
|
|
58
|
-
const d = new Date(date);
|
|
59
|
-
return d.toISOString().split('T')[0];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
16
|
async function createHtmlSitemap(hexo, force = false) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
// 校验布局
|
|
66
|
-
if (!LAYOUT_STYLES[config.layout]) {
|
|
67
|
-
hexo.log.warn(`[hexo-sitemap-html] Invalid layout: ${config.layout}, fallback to modern`);
|
|
68
|
-
config.layout = 'modern';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const nofollowAttr = config.nofollow ? 'rel="nofollow"' : '';
|
|
72
|
-
const { categories, posts, pages } = hexo.site;
|
|
17
|
+
const hexoInstance = hexo || this;
|
|
18
|
+
if (!hexoInstance) return;
|
|
73
19
|
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
20
|
+
await hexoInstance.load();
|
|
21
|
+
const urlFor = hexoInstance.extend.helper.get('url_for').bind(hexoInstance);
|
|
22
|
+
const config = _.merge({}, DEFAULT_CONFIG, (hexoInstance.config.html_sitemap || {}));
|
|
23
|
+
|
|
24
|
+
// 获取 i18n 和 CSS
|
|
25
|
+
const lang = hexoInstance.config.language || 'en';
|
|
26
|
+
const { t, css } = getTemplate(config.layout, lang);
|
|
80
27
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
path: hexo.url_for(c.path),
|
|
84
|
-
count: c.posts.length
|
|
85
|
-
})) : [];
|
|
28
|
+
const locals = hexoInstance.locals.toObject();
|
|
29
|
+
const nofollow = config.nofollow ? 'rel="nofollow"' : '';
|
|
86
30
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
title: p.title || 'Untitled Page',
|
|
92
|
-
path: hexo.url_for(p.path),
|
|
93
|
-
date: formatDate(p.date)
|
|
94
|
-
})) : [];
|
|
31
|
+
// 处理数据(逻辑同前,仅抽取数据)
|
|
32
|
+
const posts = config.enable.posts ? locals.posts.toArray().sort((a,b)=>b.date-a.date) : [];
|
|
33
|
+
const cats = config.enable.categories ? locals.categories.toArray() : [];
|
|
34
|
+
const pages = config.enable.pages ? locals.pages.toArray().filter(p => !config.exclude.some(ex => (p.title||'').includes(ex))) : [];
|
|
95
35
|
|
|
96
|
-
|
|
97
|
-
const htmlContent = `
|
|
36
|
+
const html = `
|
|
98
37
|
<!DOCTYPE html>
|
|
99
|
-
<html lang="${
|
|
38
|
+
<html lang="${lang}">
|
|
100
39
|
<head>
|
|
101
40
|
<meta charset="UTF-8">
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
${LAYOUT_STYLES[config.layout]}
|
|
41
|
+
<title>${t.title} - ${hexoInstance.config.title}</title>
|
|
42
|
+
${css}
|
|
105
43
|
</head>
|
|
106
44
|
<body>
|
|
107
45
|
<div class="container">
|
|
108
|
-
<header>
|
|
109
|
-
<h1>Site Map</h1>
|
|
110
|
-
<p style="color: #64748b;">Total ${postList.length} posts, ${categoryList.length} categories</p>
|
|
111
|
-
</header>
|
|
112
46
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
${postList.map(item => `
|
|
118
|
-
<a href="${item.path}" class="card" ${nofollowAttr}>
|
|
119
|
-
<span class="card-title">${item.title}</span>
|
|
120
|
-
<span class="card-meta">Published: ${item.date}</span>
|
|
121
|
-
</a>
|
|
122
|
-
`).join('')}
|
|
123
|
-
</div>
|
|
124
|
-
</div>` : ''}
|
|
47
|
+
<nav style="display:flex;">
|
|
48
|
+
<a class="${config.layout === 'minimal' ? '' : 'card item-link'}" href="/">${t.home}</a>
|
|
49
|
+
<a class="${config.layout === 'minimal' ? '' : 'card item-link'}" href="javascript:history.back()">${t.back}</a>
|
|
50
|
+
</nav>
|
|
125
51
|
|
|
126
|
-
|
|
127
|
-
<div class="section">
|
|
128
|
-
<h2>Categories</h2>
|
|
129
|
-
<div class="grid">
|
|
130
|
-
${categoryList.map(item => `
|
|
131
|
-
<a href="${item.path}" class="card" ${nofollowAttr}>
|
|
132
|
-
<span class="card-title">${item.name}</span>
|
|
133
|
-
<span class="card-meta">${item.count} articles</span>
|
|
134
|
-
</a>
|
|
135
|
-
`).join('')}
|
|
136
|
-
</div>
|
|
137
|
-
</div>` : ''}
|
|
52
|
+
<h1>${t.title}</h1>
|
|
138
53
|
|
|
139
|
-
${
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<a href="${item.path}" class="card" ${nofollowAttr}>
|
|
145
|
-
<span class="card-title">${item.title}</span>
|
|
146
|
-
<span class="card-meta">Updated: ${item.date}</span>
|
|
54
|
+
${posts.length ? `<section class="section"><h2>${t.posts}</h2><div class="${config.layout === 'flat' ? 'grid' : 'list'}">
|
|
55
|
+
${posts.map(p => `
|
|
56
|
+
<div class="item">
|
|
57
|
+
<a href="${urlFor(p.path)}" class="${config.layout === 'minimal' ? '' : 'card item-link'}" ${nofollow}>
|
|
58
|
+
<span class="card-title">${p.title || 'Untitled'}</span>
|
|
147
59
|
</a>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
60
|
+
${config.layout === 'minimal' ? `<div class="dot"></div>` : ''}
|
|
61
|
+
<span class="meta card-meta">${p.date.format('YYYY-MM-DD')}</span>
|
|
62
|
+
</div>`).join('')}
|
|
63
|
+
</div></section>` : ''}
|
|
64
|
+
|
|
65
|
+
${cats.length ? `<section class="section"><h2>${t.categories}</h2><div class="${config.layout === 'flat' ? 'grid' : 'list'}">
|
|
66
|
+
${cats.map(c => `
|
|
67
|
+
<div class="item">
|
|
68
|
+
<a href="${urlFor(c.path)}" class="${config.layout === 'minimal' ? '' : 'card item-link'}" ${nofollow}>
|
|
69
|
+
<span class="card-title">${c.name}</span>
|
|
70
|
+
</a>
|
|
71
|
+
${config.layout === 'minimal' ? `<div class="dot"></div>` : ''}
|
|
72
|
+
<span class="meta card-meta">${c.posts.length} ${t.items}</span>
|
|
73
|
+
</div>`).join('')}
|
|
74
|
+
</div></section>` : ''}
|
|
151
75
|
</div>
|
|
152
76
|
</body>
|
|
153
77
|
</html>`;
|
|
154
78
|
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
await fs.writeFile(outputPath, htmlContent, 'utf8');
|
|
162
|
-
hexo.log.info(`[hexo-sitemap-html] Generated: ${config.path}`);
|
|
163
|
-
return outputPath;
|
|
79
|
+
const dest = path.join(hexoInstance.public_dir, config.path);
|
|
80
|
+
if (force && await fs.exists(dest)) await fs.unlink(dest);
|
|
81
|
+
await fs.writeFile(dest, html);
|
|
82
|
+
hexoInstance.log.info(`[hexo-sitemap-html] Generated: ${config.path} with ${config.layout} style`);
|
|
164
83
|
}
|
|
165
84
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// 生成器:hexo g 时自动运行
|
|
171
|
-
hexo.extend.generator.register('html-sitemap', function(locals) {
|
|
172
|
-
return createHtmlSitemap(this);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// 独立命令:hexo sitemap-html 运行
|
|
176
|
-
hexo.extend.command.register('sitemap-html', {
|
|
177
|
-
desc: '独立生成 HTML 站点地图',
|
|
178
|
-
options: [
|
|
179
|
-
{ name: 'force', alias: 'f', desc: '强制覆盖已有文件', type: Boolean }
|
|
180
|
-
]
|
|
181
|
-
}, async function(args) {
|
|
182
|
-
try {
|
|
183
|
-
await createHtmlSitemap(this, args.f || args.force);
|
|
184
|
-
} catch (e) {
|
|
185
|
-
this.log.error(`[hexo-sitemap-html] Failed: ${e.message}`);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
};
|
|
85
|
+
hexo.extend.generator.register('html-sitemap', function() { return createHtmlSitemap(this); });
|
|
86
|
+
hexo.extend.console.register('sitemap-html', 'Generate HTML sitemap', {
|
|
87
|
+
options: [{ name: '-f, --force', desc: 'Overwrite' }]
|
|
88
|
+
}, function(args) { return createHtmlSitemap(this, args.f || args.force); });
|
package/lib/templates.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const i18n = {
|
|
4
|
+
'zh-CN': { home:"首页",back:"返回",title: '站点地图', posts: '文章归档', categories: '分类目录', pages: '独立页面', items: '篇内容', updated: '更新于' },
|
|
5
|
+
'en': { home:"Home",back:"Back",title: 'Sitemap', posts: 'Posts', categories: 'Categories', pages: 'Pages', items: 'items', updated: 'Updated' }
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const styles = {
|
|
9
|
+
// 风格 1:极致简约 (Minimal) - 衬线体、大留白、呼吸感
|
|
10
|
+
minimal: `
|
|
11
|
+
<style>
|
|
12
|
+
:root { --accent: #111; --text: #1a1a1a; --light: #888; }
|
|
13
|
+
body { font-family: "Optima", "Georgia", serif; background: #fff; color: var(--text); padding: 80px 10%; line-height: 1.8; }
|
|
14
|
+
.container { max-width: 800px; margin: 0 auto; }
|
|
15
|
+
h1 { font-size: 3.5rem; font-weight: 300; margin-bottom: 60px; letter-spacing: -2px; }
|
|
16
|
+
h2 { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 4px; color: var(--light); margin-top: 60px; border: none; }
|
|
17
|
+
.list { list-style: none; padding: 0; }
|
|
18
|
+
.item { display: flex; align-items: baseline; margin-bottom: 12px; }
|
|
19
|
+
.item a { text-decoration: none; color: var(--text); font-size: 1.15rem; transition: 0.3s; border-bottom: 1px solid transparent; }
|
|
20
|
+
.item a:hover { border-bottom: 1px solid var(--accent); }
|
|
21
|
+
.dot { flex: 1; border-bottom: 1px dotted #ececec; margin: 0 15px; }
|
|
22
|
+
.meta { font-size: 0.85rem; color: var(--light); font-style: italic; font-family: sans-serif; }
|
|
23
|
+
</style>
|
|
24
|
+
`,
|
|
25
|
+
// 风格 2:扁平克制 (Flat) - 非衬线体、灰度层次、现代感
|
|
26
|
+
flat: `
|
|
27
|
+
<style>
|
|
28
|
+
:root { --bg: #f9f9fb; --primary: #000; --text: #111; --border: #eaeaea; }
|
|
29
|
+
body { font-family: -apple-system, system-ui, sans-serif; background: var(--bg); color: var(--text); padding: 40px; }
|
|
30
|
+
.container { max-width: 1000px; margin: 0 auto; background: #fff; padding: 50px; border: 1px solid var(--border); border-radius: 4px; }
|
|
31
|
+
h1 { font-size: 24px; font-weight: 600; margin-bottom: 30px; }
|
|
32
|
+
h2 { font-size: 14px; font-weight: 600; color: #666; margin: 40px 0 20px; text-transform: uppercase; }
|
|
33
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; }
|
|
34
|
+
.card { display: block; padding: 16px; border: 1px solid var(--border); text-decoration: none; color: inherit; transition: 0.2s; }
|
|
35
|
+
.card:hover { border-color: var(--primary); background: #fafafa; }
|
|
36
|
+
.card-title { font-weight: 500; display: block; margin-bottom: 4px; }
|
|
37
|
+
.card-meta { font-size: 12px; color: #999; }
|
|
38
|
+
</style>
|
|
39
|
+
`,
|
|
40
|
+
// 风格 3:丰富视觉 (Rich) - 渐变、毛玻璃、动态感
|
|
41
|
+
rich: `
|
|
42
|
+
<style>
|
|
43
|
+
body { background: #f0f2f5; font-family: "Segoe UI", system-ui; padding: 60px 20px; }
|
|
44
|
+
.container { max-width: 900px; margin: 0 auto; }
|
|
45
|
+
h1 { font-size: 3rem; text-align: center; margin-bottom: 50px; background: linear-gradient(45deg, #007aff, #00c6ff); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
|
46
|
+
.section { background: rgba(255,255,255,0.7); backdrop-filter: blur(20px); border-radius: 20px; padding: 30px; margin-bottom: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.05); }
|
|
47
|
+
h2 { color: #333; margin-bottom: 20px; padding-left: 12px; border-left: 5px solid #007aff; }
|
|
48
|
+
.item-link { display: flex; justify-content: space-between; padding: 15px; border-radius: 12px; text-decoration: none; color: #444; transition: all 0.3s; margin-bottom: 5px; }
|
|
49
|
+
.item-link:hover { background: #fff; transform: scale(1.02); box-shadow: 0 5px 15px rgba(0,0,0,0.05); color: #007aff; }
|
|
50
|
+
</style>
|
|
51
|
+
`
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = function(layout, lang = 'en') {
|
|
55
|
+
const t = i18n[lang] || i18n['en'];
|
|
56
|
+
const css = styles[layout] || styles.flat;
|
|
57
|
+
return { t, css };
|
|
58
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hexo-sitemap-html",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
7
|
},
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js",
|
|
10
|
+
"lib/templates.js"
|
|
11
|
+
],
|
|
8
12
|
"keywords": [
|
|
9
13
|
"hexo",
|
|
10
14
|
"hexo-plugin",
|
|
@@ -17,7 +21,7 @@
|
|
|
17
21
|
"hexo": {
|
|
18
22
|
"version": ">=3.0.0"
|
|
19
23
|
},
|
|
20
|
-
"author": "2winter",
|
|
24
|
+
"author": "2winter <2winter.dev@gmail.com> (https://2winter.com)",
|
|
21
25
|
"license": "MIT",
|
|
22
26
|
"description": "A Hexo plugin to generate customizable HTML format sitemap, support controlling categories/posts/pages generation, excluding specified pages and multiple layout styles.",
|
|
23
27
|
"dependencies": {
|
package/.gitattributes
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
-
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
-
|
|
4
|
-
name: Node.js Package
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
release:
|
|
8
|
-
types: [created]
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v4
|
|
15
|
-
- uses: actions/setup-node@v4
|
|
16
|
-
with:
|
|
17
|
-
node-version: 20
|
|
18
|
-
- run: npm ci
|
|
19
|
-
- run: npm test
|
|
20
|
-
|
|
21
|
-
publish-npm:
|
|
22
|
-
needs: build
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v4
|
|
26
|
-
- uses: actions/setup-node@v4
|
|
27
|
-
with:
|
|
28
|
-
node-version: 20
|
|
29
|
-
registry-url: https://registry.npmjs.org/
|
|
30
|
-
- run: npm ci
|
|
31
|
-
- run: npm publish
|
|
32
|
-
env:
|
|
33
|
-
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
package/docs/en-US/README.md
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# hexo-sitemap-html
|
|
3
|
-
|
|
4
|
-
A **modern, responsive, and highly configurable** Hexo plugin to generate elegant HTML sitemaps. Fully compatible with **Node 22+** and **Hexo 6.x**.
|
|
5
|
-
|
|
6
|
-
> 📌 [中文版本 (Chinese Version)](../zh-CN/README.md)
|
|
7
|
-
|
|
8
|
-
## ✨ Core Features
|
|
9
|
-
|
|
10
|
-
* 🚀 **Node 22 Ready**: Uses the modern `module.exports` pattern to ensure perfect compatibility with the latest Node.js environments.
|
|
11
|
-
* 📱 **Responsive Design**: Brand new `modern` layout with a card-grid system that looks great on mobile and desktop.
|
|
12
|
-
* 🔗 **Auto Menu Injection**: Automatically injects a "Sitemap" link into your theme's navigation bar (supports most mainstream themes).
|
|
13
|
-
* 📝 **Flexible Configuration**: Independently enable/disable categories, posts, or pages.
|
|
14
|
-
* 🚫 **Fuzzy Exclusion**: Precisely exclude unwanted pages (e.g., 404, tags) using keywords in titles or paths.
|
|
15
|
-
* 🎨 **Multiple Layouts**: Built-in styles including `Modern`, `Simple`, and `Rich`.
|
|
16
|
-
* 🔧 **Native UTF-8**: Zero garbled characters, perfect for CJK (Chinese, Japanese, Korean) content.
|
|
17
|
-
|
|
18
|
-
## 📦 Installation
|
|
19
|
-
|
|
20
|
-
### Method 1: Local Development (Manual)
|
|
21
|
-
|
|
22
|
-
If you are developing or customizing the plugin:
|
|
23
|
-
|
|
24
|
-
1. In your Hexo blog root, create the folder: `node_modules/hexo-sitemap-html`.
|
|
25
|
-
2. Place `index.js` and `package.json` inside.
|
|
26
|
-
3. In your **blog root**, run:
|
|
27
|
-
```bash
|
|
28
|
-
npm install ./node_modules/hexo-sitemap-html
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
### Method 2: Via npm (Standard)
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npm install hexo-sitemap-html --save
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## ⚙️ Configuration
|
|
42
|
-
|
|
43
|
-
Add the following to your Hexo root `_config.yml`:
|
|
44
|
-
|
|
45
|
-
```yaml
|
|
46
|
-
# hexo-sitemap-html Configuration
|
|
47
|
-
html_sitemap:
|
|
48
|
-
path: 'sitemap.html' # Output path
|
|
49
|
-
layout: 'modern' # Options: modern, simple, rich
|
|
50
|
-
inject_menu: true # Auto-add "Sitemap" to your blog navigation
|
|
51
|
-
nofollow: true # Add rel="nofollow" to sitemap links
|
|
52
|
-
|
|
53
|
-
enable:
|
|
54
|
-
categories: true # Show categories section
|
|
55
|
-
posts: true # Show posts section
|
|
56
|
-
pages: true # Show standalone pages section
|
|
57
|
-
|
|
58
|
-
exclude: # Fuzzy match title or path to hide pages
|
|
59
|
-
- '404'
|
|
60
|
-
- 'guestbook'
|
|
61
|
-
- 'About Me'
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Configuration Details
|
|
66
|
-
|
|
67
|
-
| Option | Type | Default | Description |
|
|
68
|
-
| --- | --- | --- | --- |
|
|
69
|
-
| `path` | String | `sitemap.html` | The filename of the generated sitemap. |
|
|
70
|
-
| `layout` | String | `modern` | UI Style: `modern` (Grid), `simple` (List), `rich` (Animated Cards). |
|
|
71
|
-
| `inject_menu` | Boolean | `false` | Dynamically injects the sitemap link into `theme.menu`. |
|
|
72
|
-
| `nofollow` | Boolean | `false` | If true, search engines won't follow the sitemap links. |
|
|
73
|
-
| `exclude` | Array | `[]` | Keywords to filter out specific pages from the sitemap. |
|
|
74
|
-
|
|
75
|
-
## 🚀 Usage
|
|
76
|
-
|
|
77
|
-
1. Clean and generate:
|
|
78
|
-
```bash
|
|
79
|
-
hexo clean && hexo generate
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
2. Start local server:
|
|
85
|
-
```bash
|
|
86
|
-
hexo server
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
3. Visit: `http://localhost:4000/sitemap.html`
|
|
92
|
-
|
|
93
|
-
## 🎨 Layout Previews
|
|
94
|
-
|
|
95
|
-
### 1. Modern Layout (New!)
|
|
96
|
-
|
|
97
|
-
* **Features**: CSS-Grid card system, mobile-friendly, clean typography.
|
|
98
|
-
* **Best for**: Modern tech blogs and large portfolios.
|
|
99
|
-
|
|
100
|
-
### 2. Simple Layout
|
|
101
|
-
|
|
102
|
-
* **Features**: Minimalist text list, fast loading, no-distraction design.
|
|
103
|
-
* **Best for**: Personal diaries or minimal sites.
|
|
104
|
-
|
|
105
|
-
### 3. Rich Layout
|
|
106
|
-
|
|
107
|
-
* **Features**: Card-based design with hover animations and deeper shadows.
|
|
108
|
-
* **Best for**: Visually-driven blogs.
|
|
109
|
-
|
|
110
|
-
## ❓ FAQ
|
|
111
|
-
|
|
112
|
-
### Q1: The Sitemap is not showing in my Menu?
|
|
113
|
-
|
|
114
|
-
A: `inject_menu` works by modifying `theme.config.menu` in memory. If your theme uses a non-standard menu structure (not `menu` or `navbar`), you may need to add the link manually to your theme's `_config.yml`.
|
|
115
|
-
|
|
116
|
-
### Q2: Is it compatible with Node 22?
|
|
117
|
-
|
|
118
|
-
A: Yes! This version uses the Dependency Injection pattern (`module.exports = function(hexo)...`) which is the safest way to handle plugins in Node 22/Hexo 6.
|
|
119
|
-
|
|
120
|
-
### Q3: How to customize the CSS?
|
|
121
|
-
|
|
122
|
-
A: You can find the `<style>` tags in `index.js` under the `LAYOUT_STYLES` constant. Feel free to modify the colors or fonts to match your specific theme.
|
|
123
|
-
|
|
124
|
-
## 🤝 Contributing
|
|
125
|
-
|
|
126
|
-
1. Fork the repo.
|
|
127
|
-
2. Create your branch (`git checkout -b feature/AmazingFeature`).
|
|
128
|
-
3. Commit (`git commit -m 'Add some feature'`).
|
|
129
|
-
4. Push to the branch and open a Pull Request.
|
|
130
|
-
|
|
131
|
-
## 📄 License
|
|
132
|
-
|
|
133
|
-
This project is licensed under the **MIT License**.
|
package/docs/zh-CN/README.md
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# hexo-sitemap-html
|
|
4
|
-
|
|
5
|
-
一个**现代、响应式、高度可配置**的 Hexo 插件,用于生成美观的 HTML 格式站点地图。完美适配 **Node 22+** 和 **Hexo 6.x**。
|
|
6
|
-
|
|
7
|
-
> 📌 语言切换:[English Version](../en-US/README.md)
|
|
8
|
-
|
|
9
|
-
## ✨ 核心特性
|
|
10
|
-
|
|
11
|
-
* 🚀 **适配 Node 22**:采用现代的 `module.exports` 插件导出模式,解决新版本 Node 环境下的作用域与全局变量注入问题。
|
|
12
|
-
* 📱 **响应式设计**:全新的 `modern` 布局,采用网格系统(Grid),完美适配手机和电脑端浏览。
|
|
13
|
-
* 🔗 **菜单自动注入**:支持将站点地图链接自动插入到主题的导航栏(适配 NexT, Butterfly, Fluid 等主流主题)。
|
|
14
|
-
* 📝 **灵活配置**:独立控制分类、文章、页面模块的开关。
|
|
15
|
-
* 🚫 **模糊排除**:支持通过标题或路径关键词,精准排除不需要展示的页面(如 404 页、标签页)。
|
|
16
|
-
* 🎨 **多布局风格**:内置 3 种布局(Modern 现代 / Simple 简洁 / Rich 丰富)。
|
|
17
|
-
* 🔧 **零乱码**:原生支持 UTF-8,完美适配中日韩等非 ASCII 字符。
|
|
18
|
-
|
|
19
|
-
## 📦 安装
|
|
20
|
-
|
|
21
|
-
### 方式 1:本地开发(推荐)
|
|
22
|
-
|
|
23
|
-
如果您正在开发或自定义插件:
|
|
24
|
-
|
|
25
|
-
1. 在 Hexo 博客根目录下创建目录:`node_modules/hexo-sitemap-html`。
|
|
26
|
-
2. 将 `index.js` 和 `package.json` 放入该目录。
|
|
27
|
-
3. 在**博客根目录**执行:
|
|
28
|
-
```bash
|
|
29
|
-
npm install ./node_modules/hexo-sitemap-html
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
### 方式 2:npm 安装(发布后)
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm install hexo-sitemap-html --save
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## ⚙️ 配置
|
|
43
|
-
|
|
44
|
-
在 Hexo 博客根目录的 `_config.yml` 中添加以下配置:
|
|
45
|
-
|
|
46
|
-
```yaml
|
|
47
|
-
# hexo-sitemap-html 配置
|
|
48
|
-
html_sitemap:
|
|
49
|
-
path: 'sitemap.html' # 输出路径
|
|
50
|
-
layout: 'modern' # 布局选择: modern, simple, rich
|
|
51
|
-
inject_menu: true # 自动将“站点地图”添加到博客导航栏
|
|
52
|
-
nofollow: true # 为地图链接添加 rel="nofollow",避免分散权重
|
|
53
|
-
|
|
54
|
-
enable:
|
|
55
|
-
categories: true # 显示分类
|
|
56
|
-
posts: true # 显示文章
|
|
57
|
-
pages: true # 显示独立页面
|
|
58
|
-
|
|
59
|
-
exclude: # 排除页面(模糊匹配标题或路径)
|
|
60
|
-
- '404'
|
|
61
|
-
- 'guestbook'
|
|
62
|
-
- '关于我'
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### 配置项详情
|
|
67
|
-
|
|
68
|
-
| 配置项 | 类型 | 默认值 | 说明 |
|
|
69
|
-
| --- | --- | --- | --- |
|
|
70
|
-
| `path` | String | `sitemap.html` | 生成的文件名。 |
|
|
71
|
-
| `layout` | String | `modern` | UI 风格:`modern` (响应式网格), `simple` (纯文本列表), `rich` (带动画的卡片)。 |
|
|
72
|
-
| `inject_menu` | Boolean | `false` | 是否自动修改 `theme.menu` 配置,动态注入菜单链接。 |
|
|
73
|
-
| `nofollow` | Boolean | `false` | 开启后,生成的链接会带上 `nofollow` 属性。 |
|
|
74
|
-
| `exclude` | Array | `[]` | 关键词数组,匹配到的页面将不会出现在站点地图中。 |
|
|
75
|
-
|
|
76
|
-
## 🚀 使用
|
|
77
|
-
|
|
78
|
-
1. 清除并生成:
|
|
79
|
-
```bash
|
|
80
|
-
hexo clean && hexo generate
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
2. 本地预览:
|
|
86
|
-
```bash
|
|
87
|
-
hexo server
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
3. 访问:`http://localhost:4000/sitemap.html`
|
|
93
|
-
|
|
94
|
-
## 🎨 布局风格预览
|
|
95
|
-
|
|
96
|
-
### 1. modern(现代版 - 推荐)
|
|
97
|
-
|
|
98
|
-
* **特点**:基于 CSS Grid 的卡片系统,响应式布局,极简线条感。
|
|
99
|
-
* **适用**:现代技术博客、作品集。
|
|
100
|
-
|
|
101
|
-
### 2. simple(简洁版)
|
|
102
|
-
|
|
103
|
-
* **特点**:无装饰列表,加载速度最快。
|
|
104
|
-
* **适用**:追求极致简约或极简风主题。
|
|
105
|
-
|
|
106
|
-
### 3. rich(丰富版)
|
|
107
|
-
|
|
108
|
-
* **特点**:带悬浮阴影(Hover Shadow)的深色卡片设计。
|
|
109
|
-
* **适用**:视觉表现力强的主题。
|
|
110
|
-
|
|
111
|
-
## ❓ 常见问题
|
|
112
|
-
|
|
113
|
-
### Q1: 导航栏没有出现“站点地图”链接?
|
|
114
|
-
|
|
115
|
-
A: `inject_menu` 功能通过内存修改主题配置实现。如果你的主题导航栏配置非常特殊(非 `menu` 或 `navbar` 字段),可能无法自动注入。建议在主题配置中手动添加一行链接。
|
|
116
|
-
|
|
117
|
-
### Q2: 兼容 Node 22 吗?
|
|
118
|
-
|
|
119
|
-
A: 是的。针对 Node 22 严格模式下全局 `hexo` 变量获取不到的问题,本项目采用了 Dependency Injection(依赖注入)模式重新编写了入口逻辑。
|
|
120
|
-
|
|
121
|
-
### Q3: 这会影响 SEO 吗?
|
|
122
|
-
|
|
123
|
-
A: 不会。此插件生成的 HTML 地图是给**人**看的(方便读者快速定位内容)。如果你需要给搜索引擎看的地图,请同时安装 `hexo-generator-sitemap` 生成 `sitemap.xml`。
|
|
124
|
-
|
|
125
|
-
## 📄 许可证
|
|
126
|
-
|
|
127
|
-
本项目采用 **MIT** 许可证。
|
|
128
|
-
|