diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ea8d8a0..519a1e1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -40,11 +40,11 @@ jobs: - name: Check favicon run: | - if [ -f favicon.ico ]; then + if [ -f dist/favicon.ico ]; then echo "Favicon exists" - ls -l favicon.ico + ls -l dist/favicon.ico else - echo "Warning: favicon.ico not found" + echo "Warning: favicon.ico not found in dist directory" exit 1 fi @@ -54,7 +54,7 @@ jobs: - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - path: '.' + path: 'dist' deploy: environment: diff --git a/.gitignore b/.gitignore index 41e6558..63e6c1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,16 @@ -# 依赖目录 +# 依赖相关 node_modules/ npm-debug.log* -yarn-debug.log* -yarn-error.log* -# IDE 配置 +# 构建输出 +dist/ + +# IDE/编辑器配置 .vscode/ .idea/ -*.sublime-project -*.sublime-workspace .specstory .cursorindexingignore # 系统文件 .DS_Store Thumbs.db - -# 环境变量 -.env -.env.local -.env.*.local - -# 日志文件 -*.log -logs/ - -# 用户配置文件 -config.user.yml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 82d21c7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,66 +0,0 @@ -# 更新日志 - -本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/) 规范。 - -## [1.0.0] - 2024-03-20 - -### 新增 -- 基础导航页面结构 -- 深色主题设计 -- 响应式布局 -- 搜索功能 -- 多页面管理(首页、项目、文章、朋友) -- 动画效果 - -### 功能模块 -- 左侧固定导航栏 - - 主导航菜单 - - 社交媒体链接 -- 右侧内容区域 - - 搜索框 - - 分类展示 - - 网站卡片 - -### 技术实现 -- 使用HTML5语义化标签 -- CSS3现代特性 - - Flexbox布局 - - Grid系统 - - 响应式设计 - - 过渡动画 -- 原生JavaScript实现 - - 页面切换 - - 搜索过滤 - - 动画控制 - -### 优化 -- 移动端适配 -- 性能优化 -- 代码结构优化 - -### 文档 -- 添加README.md -- 添加开发文档 -- 添加贡献指南 -- 添加更新日志 - -## [0.1.0] - 2025-01-31 - -### 新增 -- 项目初始化 -- 基础文件结构 -- 开发环境配置 - -## [1.2.3] - 2024-03-21 - -### 优化 -- 改进GitHub Pages部署流程 - - 使用官方推荐的部署方式 - - 添加自动化部署配置 - - 优化构建缓存 -- 更新依赖管理 - - 添加开发服务器支持 - - 优化依赖版本控制 -- 改进项目配置 - - 优化.gitignore规则 - - 添加homepage配置 \ No newline at end of file diff --git a/README.md b/README.md index 59dd59e..9491e0c 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,23 @@ - Font Awesome 图标 - GitHub Pages / Cloudflare Pages 托管 +## 项目结构 + +``` +menav/ +├── assets/ # 静态资源文件 +│ ├── style.css # 样式表 +│ └── favicon.ico # 网站图标 +├── src/ # 源代码 +│ ├── generator.js # 静态网站生成器 +│ └── script.js # 前端JavaScript脚本 +├── templates/ # HTML模板 +│ └── index.html # HTML骨架模板文件 +├── dist/ # 生成的静态网站(由generator.js生成) +├── config.yml # 默认配置文件 +└── config.user.yml # 用户自定义配置文件 +``` + ## 快速开始 1. 克隆仓库 @@ -41,12 +58,14 @@ npm install ``` 3. 修改配置 -编辑 `config.yml` 文件,根据你的需求修改网站内容: -- 修改网站基本信息 -- 添加/修改导航链接 -- 自定义社交媒体链接 -- 更新个人项目展示 -- 添加友情链接等 +- 复制 `config.yml` 为 `config.user.yml` +- 在 `config.user.yml` 中根据你的需求修改网站内容: + - 修改网站基本信息 + - 添加/修改导航链接 + - 自定义社交媒体链接 + - 更新个人项目展示 + - 添加友情链接等 + 4. 本地预览 ```bash @@ -82,7 +101,7 @@ npm run dev 1. 创建个人配置文件: - 复制 `config.yml` 为 `config.user.yml` - 在 `config.user.yml` 中修改配置 - - 这样在后续同步更新时,您的配置不会被覆盖 + - 提交 `config.user.yml` 到您的仓库,这样GitHub Actions才能使用您的自定义配置进行构建 2. 修改配置信息: - 修改网站基本信息 @@ -93,7 +112,7 @@ npm run dev 完成以上步骤后,系统会自动部署您的网站。部署完成后,您可以在 Settings -> Pages 中找到您的网站地址。 -> 重要提示: 请务必使用 `config.user.yml` 进行配置,这样在同步上游更新时不会丢失您的个人设置。 +> 重要提示: 请务必使用 `config.user.yml` 进行配置,这样在同步上游更新时不会丢失您的个人设置。同时注意不要在配置文件中包含敏感信息,因为它将被提交到公开仓库。 #### 故障排除 @@ -116,25 +135,29 @@ npm run dev - 构建输出目录: `/` - Node.js 版本: `16`或更高 -## 自定义配置 -### 配置文件说明 +### 模板说明 -本项目提供两种配置文件: -1. `config.yml` - 默认配置模板,会随项目更新 -2. `config.user.yml` - 用户个人配置,不会被项目更新覆盖 +本项目使用模板与配置文件分离的方式生成网站: -建议使用步骤: -1. 复制 `config.yml` 为 `config.user.yml` -2. 在 `config.user.yml` 中进行个性化配置 -3. 原始的 `config.yml` 保持不变 -4. 后续同步更新时,您的个人配置不会被覆盖 +1. `templates/index.html` 是不包含具体内容的HTML骨架模板: + - 使用占位符 (如 `{{SITE_TITLE}}`, `{{NAVIGATION}}`, `{{HOME_CONTENT}}`) 标记动态内容的位置 + - 只包含页面结构、CSS引用和基本Javascript引用 + +2. 工作原理: + - `generator.js` 读取配置文件 (优先使用 `config.user.yml`) + - 将配置内容注入到模板中的占位符位置 + - 生成最终的静态HTML网站 + +3. 优点: + - 清晰分离结构与内容 + - 用户只需修改配置文件,不需要编辑HTML + - 便于更新与维护 -> 注意: `config.user.yml` 已添加到 .gitignore 中,不会被提交到仓库 ### 配置文件结构 -`config.yml` 包含以下主要部分: +`config.user.yml` 应包含以下主要部分: ```yaml # 网站基本信息 @@ -210,28 +233,28 @@ fonts: 1. 准备图标文件: - 支持.ico、.png等格式 - 建议尺寸为32x32或16x16像素 - - 将图标文件放在仓库根目录 - - 例如: `favicon.ico` 或 `favicon.png` + - 将图标文件放在assets目录下 + - 例如: `assets/favicon.ico` 或 `assets/favicon.png` 2. 配置图标: - 在`config.yml`或`config.user.yml`的site部分设置favicon - 使用相对于仓库根目录的路径 - - 例如: `favicon: favicon.ico` + - 例如: `favicon: favicon.ico`(generator会自动从assets目录查找) - 也可以使用在线图标URL 3. 生成和部署: - - 运行 `npm run generate` 时会自动复制图标文件 - - 确保图标文件存在于指定位置 + - 运行 `npm run generate` 时会自动复制图标文件到dist目录 + - 确保图标文件存在于assets目录中 - 部署后图标会自动显示在浏览器标签页 > 提示: 如果图标没有显示,请检查: -> 1. 图标文件是否存在于正确位置 +> 1. 图标文件是否存在于assets目录 > 2. 配置文件中的路径是否正确 > 3. 是否重新运行了生成命令 ### 添加新的网站链接 -在 `config.yml` 中相应的分类下添加新站点: +在 `config.user.yml` 中相应的分类下添加新站点: ```yaml categories: @@ -244,11 +267,6 @@ categories: description: 网站描述 ``` -## 版本 - -当前版本: v1.2.3 - -查看 [CHANGELOG.md](./CHANGELOG.md) 了解详细的更新历史。 ## 贡献 diff --git a/favicon.ico b/assets/favicon.ico similarity index 100% rename from favicon.ico rename to assets/favicon.ico diff --git a/style.css b/assets/style.css similarity index 100% rename from style.css rename to assets/style.css diff --git a/config.yml b/config.yml index 05d8f21..4cec57d 100644 --- a/config.yml +++ b/config.yml @@ -4,6 +4,7 @@ site: description: 个人网络导航站 author: Your Name favicon: favicon.ico # 网站图标,支持ico、png等格式 + logo_text: 导航站 # 左侧导航栏Logo文字 # 字体设置 fonts: @@ -62,6 +63,10 @@ categories: - name: 常用网站 icon: fas fa-star sites: + - name: Linux.do + url: https://linux.do/ + icon: fab fa-linux + description: 新的理想型社区 - name: Google url: https://www.google.com icon: fab fa-google diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to docs/CONTRIBUTING.md diff --git a/DEVELOPMENT.md b/docs/DEVELOPMENT.md similarity index 100% rename from DEVELOPMENT.md rename to docs/DEVELOPMENT.md diff --git a/index.html b/index.html deleted file mode 100644 index 515b712..0000000 --- a/index.html +++ /dev/null @@ -1,678 +0,0 @@ - - - - - - 我的导航 - - - - - - - - -
- -
- - -
- - -
- - - - - -
- -
- -
- - - - - - - - - - - - - - -
-
-

搜索结果

-

在所有页面中找到的匹配项

-
- - - - - - - - -
-
-
- - - - - \ No newline at end of file diff --git a/package.json b/package.json index 5915744..c603e7b 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,14 @@ "name": "menav", "version": "1.2.3", "description": "A personal navigation website", - "main": "generator.js", + "main": "src/generator.js", "homepage": "https://rbetree.github.io/menav", "scripts": { - "generate": "node generator.js", - "dev": "node generator.js && serve .", - "clean": "rm -rf index.html" + "generate": "node src/generator.js", + "dev": "node src/generator.js && serve dist", + "clean": "rm -rf dist", + "build": "npm run clean && npm run generate", + "restructure": "node restructure.js" }, "keywords": [ "navigation", @@ -29,4 +31,4 @@ "devDependencies": { "serve": "^14.2.1" } -} \ No newline at end of file +} \ No newline at end of file diff --git a/generator.js b/src/generator.js similarity index 73% rename from generator.js rename to src/generator.js index 8743ea5..996c317 100644 --- a/generator.js +++ b/src/generator.js @@ -108,6 +108,17 @@ function generateSocialLinks(social) { `).join('\n'); } +// 生成欢迎区域和首页内容 +function generateHomeContent(config) { + return ` +
+

${escapeHtml(config.profile.title)}

+

${escapeHtml(config.profile.subtitle)}

+

${escapeHtml(config.profile.description)}

+
+${generateCategories(config.categories)}`; +} + // 生成页面内容 function generatePageContent(pageId, data) { return ` @@ -286,12 +297,36 @@ ${generateSearchResultsPage(config)} // 复制静态文件 function copyStaticFiles(config) { + // 确保dist目录存在 + if (!fs.existsSync('dist')) { + fs.mkdirSync('dist', { recursive: true }); + } + + // 复制CSS文件 + try { + fs.copyFileSync('assets/style.css', 'dist/style.css'); + console.log('Copied style.css to dist/'); + } catch (e) { + console.error('Error copying style.css:', e); + } + + // 复制JavaScript文件 + try { + fs.copyFileSync('src/script.js', 'dist/script.js'); + console.log('Copied script.js to dist/'); + } catch (e) { + console.error('Error copying script.js:', e); + } + // 如果配置了favicon,确保文件存在并复制 if (config.site.favicon) { try { - if (fs.existsSync(config.site.favicon)) { - fs.copyFileSync(config.site.favicon, path.basename(config.site.favicon)); - console.log(`Copied favicon: ${config.site.favicon}`); + if (fs.existsSync(`assets/${config.site.favicon}`)) { + fs.copyFileSync(`assets/${config.site.favicon}`, `dist/${path.basename(config.site.favicon)}`); + console.log(`Copied favicon: ${config.site.favicon} to dist/`); + } else if (fs.existsSync(config.site.favicon)) { + fs.copyFileSync(config.site.favicon, `dist/${path.basename(config.site.favicon)}`); + console.log(`Copied favicon: ${config.site.favicon} to dist/`); } else { console.warn(`Warning: Favicon file not found: ${config.site.favicon}`); } @@ -301,15 +336,65 @@ function copyStaticFiles(config) { } } +// 处理模板文件,替换占位符 +function processTemplate(template, config) { + const currentYear = new Date().getFullYear(); + const googleFontsLink = generateGoogleFontsLink(config); + const fontVariables = generateFontVariables(config); + + // 创建替换映射 + const replacements = { + '{{SITE_TITLE}}': escapeHtml(config.site.title), + '{{SITE_LOGO_TEXT}}': escapeHtml(config.site.logo_text || '导航站'), // 从配置中获取,如果不存在则使用默认值 + '{{GOOGLE_FONTS}}': googleFontsLink, + '{{{FONT_VARIABLES}}}': fontVariables, + '{{NAVIGATION}}': generateNavigation(config.navigation), + '{{SOCIAL_LINKS}}': generateSocialLinks(config.social), + '{{CURRENT_YEAR}}': currentYear, + '{{HOME_CONTENT}}': generateHomeContent(config), + '{{PROJECTS_CONTENT}}': generatePageContent('projects', config.projects), + '{{ARTICLES_CONTENT}}': generatePageContent('articles', config.articles), + '{{FRIENDS_CONTENT}}': generatePageContent('friends', config.friends), + '{{SEARCH_RESULTS}}': generateSearchResultsPage(config) + }; + + // 执行替换 + let processedTemplate = template; + for (const [placeholder, value] of Object.entries(replacements)) { + processedTemplate = processedTemplate.replace(placeholder, value); + } + + return processedTemplate; +} + // 主函数 function main() { const config = loadConfig(); - const html = generateHTML(config); try { + // 确保dist目录存在 + if (!fs.existsSync('dist')) { + fs.mkdirSync('dist', { recursive: true }); + } + + // 读取模板文件 + const templatePath = 'templates/index.html'; + let htmlContent = ''; + + if (fs.existsSync(templatePath)) { + // 读取模板并处理 + const template = fs.readFileSync(templatePath, 'utf8'); + htmlContent = processTemplate(template, config); + console.log(`Using template from ${templatePath} and injecting content`); + } else { + // 如果没有模板文件,使用生成的HTML + htmlContent = generateHTML(config); + console.log('No template file found, using generated HTML'); + } + // 生成HTML - fs.writeFileSync('index.html', html); - console.log('Successfully generated index.html'); + fs.writeFileSync('dist/index.html', htmlContent); + console.log('Successfully generated dist/index.html'); // 复制静态文件 copyStaticFiles(config); diff --git a/script.js b/src/script.js similarity index 100% rename from script.js rename to src/script.js diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..a9bb2d0 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,89 @@ + + + + + + {{SITE_TITLE}} + + + {{GOOGLE_FONTS}} + + + + + +
+ +
+ + +
+ + +
+ + + + + +
+ +
+ +
+ + +
+ {{HOME_CONTENT}} +
+ + +
+ {{PROJECTS_CONTENT}} +
+ + +
+ {{ARTICLES_CONTENT}} +
+ + +
+ {{FRIENDS_CONTENT}} +
+ + {{SEARCH_RESULTS}} +
+
+ + + \ No newline at end of file