Skip to content

Commit

Permalink
Merge pull request #6 from ChengCheng0v0/develop
Browse files Browse the repository at this point in the history
v2.0.3 版本开发完毕
  • Loading branch information
ChengCheng0v0 authored Nov 3, 2024
2 parents ea07b80 + 16161ae commit cc25e84
Show file tree
Hide file tree
Showing 10 changed files with 516 additions and 81 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@ node_modules/
*.code-workspace
.vscode/


assets/themes/liora
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@
使用配置文件还有一个好处就是你可以非常轻松地进行版本升级,每次更新的时候只需要对配置文件进行手动修改就可以做到基本内容的无缝切换。
关于如何修改网站配置,请参见下面的 [如何使用/修改网站配置](#修改网站配置) 章节。

网站的内容和公告区域是使用 [Marked](https://github.com/markedjs/marked) 将 Markdown 渲染为 HTML 的(就像 GitHub 主页的 README 一样),这么做的好处是大大降低了网站编写的复杂性,并且这个渲染器不会过滤掉 HTML 内容(这意味着你只需要编写简短的 Markdown 文档就可以做出复杂的页面内容!)。
网站的内容和公告区域是使用 [markdown-it](https://github.com/markdown-it/markdown-it) 将 Markdown 渲染为 HTML 的(就像 GitHub 主页的 README 一样),这么做的好处是大大降低了网站编写的复杂性,并且这个渲染器不会过滤掉 HTML 内容(这意味着你只需要编写简短的 Markdown 文档就可以做出复杂的页面内容!)。

项目的代码有着较高的可读性,加上其内容与 HTML 样式分离的设计使得你可以轻松地将它修改成你想要的样子!
网站只有一个简单的最小化框架,你可以在这个基础上增加任何你喜欢的内容,而不会被大型项目的局限性和复杂性所影响。

这个项目目前正处在重构后的第一个大版本!所以未来还会在保留当前设计理念的情况下增加很多模块化的功能,如果感兴趣的话欢迎点个 Star 和关注,谢谢!\(>▽

有任何问题欢迎提 Issue!有希望添加的功能或者有任何建议的话让我们 Discussions 见
有任何问题欢迎提 Issue!有希望添加的功能或者有任何建议的话请发起讨论

### 使用的项目

- 语言: 前端三件套 (HTML, CSS, JavaScript)
- Markdown 渲染器: [Marked.js](https://github.com/markedjs/marked)
- Markdown 渲染器: [markdown-it.js](https://github.com/markdown-it/markdown-it)
- 文本打字效果: [Typed.js](https://github.com/mattboldt/typed.js)
- 字体图标: FontAwesome
- 字体: Linotte + 汉仪正圆
Expand Down Expand Up @@ -67,14 +67,14 @@
<div class="markdown-content" src="./assets/markdown/content-page.md"></div>
```

这段代码使用了一个纯净的 `div` 元素来包裹内容,Marked 解析后的 HTML 元素都将插入到这个 `div` 中。
这段代码使用了一个纯净的 `div` 元素来包裹内容,markdown-it 解析后的 HTML 元素都将插入到这个 `div` 中。
`src` 属性定义了需要渲染的源 `.md` 文件的相对或绝对路径。这个路径指向的可以是一个本地 URL 也可以是一个远程 URL,渲染器会通过 `fetch` 获取 Markdown 源文件并进行渲染。

因为渲染器会在页面 DOM 加载完成的时候查找页面内的所有 `.markdown-content` 元素并将其指定的内容渲染出来,所以你可以在页面内任何地方插入这样的元素!

项目中自带了两个需要渲染的 Markdown 文件:`/assets/markdown/content-page.md``/assets/markdown/announcement.md`,它们分别存放了网页主要内容区域和侧边栏公告卡片的 Markdown 内容。

关于渲染器的更多可自定义选项,请查看 [Marked.js](https://github.com/markedjs/marked) 的官方文档!我会在未来为这个项目加入更多可用的扩展 Markdown 语法。
关于渲染器的更多可自定义选项,请查看 [markdown-it.js](https://github.com/markdown-it/markdown-it) 的官方文档!

### 编写主要内容区域的 Markdown 文档时的最佳实践

Expand Down
24 changes: 11 additions & 13 deletions assets/scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ document.addEventListener("alpine:init", () => {
});

document.addEventListener("DOMContentLoaded", async () => {
// 获取 DOM 元素
var element = {
socialIcons: document.querySelector(".social-icons"),
icpInfo: document.querySelector(".icp-info"),
webmasterInfo: document.querySelector(".webmaster-info"),
};

// 设置网站标题
document.title = config.content.title;

Expand All @@ -32,9 +39,6 @@ document.addEventListener("DOMContentLoaded", async () => {

/* 生成社交链接图标 */

// 获取 .social-icons 元素
const socialIconsElement = document.querySelector(".social-icons");

// 创建一个数组,用来存放生成的链接 HTML
const socialIconLinks = config.content.masterInfo.socialLink.enable
.map((key) => {
Expand All @@ -49,7 +53,7 @@ document.addEventListener("DOMContentLoaded", async () => {
.filter(Boolean); // 过滤掉无效的值

// 将生成的链接插入到 .social-icons 元素中
socialIconsElement.innerHTML = socialIconLinks.join("");
element.socialIcons.innerHTML = socialIconLinks.join("");

/* 生成社交链接图标 End */

Expand All @@ -65,9 +69,6 @@ document.addEventListener("DOMContentLoaded", async () => {

/* 生成页脚 ICP 备案信息 */

// 获取 .icp-info 元素
const icpInfoElement = document.querySelector(".icp-info");

// 创建一个数组,用来存放生成的链接 HTML
const icpInfoLinks = config.content.icp.enable
.map((key) => {
Expand All @@ -82,18 +83,15 @@ document.addEventListener("DOMContentLoaded", async () => {
.filter(Boolean); // 过滤掉无效的值

// 将生成的链接用 fa-shield 图标连接,并插入到 .icp-info 元素中
icpInfoElement.innerHTML = icpInfoLinks.join(` <i class="fa-solid fa-shield"></i> `);
element.icpInfo.innerHTML = icpInfoLinks.join(` <i class="fa-solid fa-shield"></i> `);

/* 生成页脚 ICP 备案信息 End */

/* 检测页脚的重复作者名称并修正 */ // (好像没啥用

// 获取 .webmaster-info 元素
const webmasterInfoElement = document.querySelector(".webmaster-info");

// 球球你别改这里可以嘛呜呜呜 (>﹏<)
if (config.content.masterInfo.name === "成成0v0") {
// 球球你别改这里可以嘛呜呜呜 (>﹏<)
webmasterInfoElement.innerHTML = "";
element.webmasterInfo.innerHTML = "";
}

/* 检测页脚的重复作者名称并修正 End */
Expand Down
85 changes: 66 additions & 19 deletions assets/scripts/theme-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
var themePath;
var metaData;

// 配色方案切换加载动画的最短显示时间
const minimumColorSwitchTime = 650;
const colorSwitchSleepTime = 310;

class ThemeManager {
constructor() {
this.parse();
Expand Down Expand Up @@ -156,36 +160,79 @@ class ThemeManager {

// 将生成的外部资源链接插入到 theme 元素中
document.querySelector("theme").innerHTML = resTag.join("");

console.log("%c[I]%c " + `准备执行 <theme> 中的所有 Script 脚本`, "background-color: #00896c;", "");

// 执行 <theme> 中的所有 Script 脚本
this.runScripts();
}

// 设置配色方案
setColor(colorId) {
if (colorId === localStorage.getItem("theme.color")) {
console.warn("%c[W]%c " + `当前配色方案已是 ${colorId},与其白白重载一次,不如我现在就中断更改`, "background-color: #e98b2a;", "");
} else {
// 检查索引中是否存在主题
// 保留关键字 !autoSwitch 可以不需要在索引中存在
if (metaData.colors.index.includes(colorId) || colorId === "!autoSwitch") {
try {
localStorage.setItem("theme.color", colorId);

// 重新加载主题
themeManager.load();

console.log("%c[I]%c " + `配色方案已更改为: ${colorId}`, "background-color: #00896c;", "");
} catch (error) {
console.error("%c[E]%c " + `无法将配色方案更改为 ${colorId}: ${error}`, "background-color: #cb1b45;", "");
throw new Error("配色方案更改失败: ", error);
// 隐藏滚动条
document.body.style.paddingRight = `${window.innerWidth - document.documentElement.clientWidth}px`; // 给 body 加一个与滚动条宽度相同的右边距以防止页面抖动
document.body.style.overflow = "hidden";

// 开始播放加载动画
document.getElementById("theme-color-loader-iframe").className = "start"; // 播放开始动画

// 加载配色方案
setTimeout(() => {
// 检查索引中是否存在配色方案
// 保留关键字 !autoSwitch 可以不需要在索引中存在
if (metaData.colors.index.includes(colorId) || colorId === "!autoSwitch") {
try {
localStorage.setItem("theme.color", colorId);

// 重新加载主题
themeManager.load();

console.log("%c[I]%c " + `配色方案已更改为: ${colorId}`, "background-color: #00896c;", "");
} catch (error) {
console.error("%c[E]%c " + `无法将配色方案更改为 ${colorId}: ${error}`, "background-color: #cb1b45;", "");
throw new Error("配色方案更改失败: ", error);
}
} else {
console.error("%c[E]%c " + `无法将配色方案更改为 ${colorId},因为未在主题配色方案索引中匹配到传入的值`, "background-color: #cb1b45;", "");
throw new Error("配色方案更改失败,未在主题配色方案索引中匹配到传入的值");
}
} else {
console.error("%c[E]%c " + `无法将配色方案更改为 ${colorId},因为未在主题配色方案索引中匹配到传入的值`, "background-color: #cb1b45;", "");
throw new Error("配色方案更改失败,未在主题配色方案索引中匹配到传入的值");
}

// 加载配色方案设置的选中效果
loadThemeSelEff();
// 加载配色方案设置的选中效果
loadThemeSelEff();
}, colorSwitchSleepTime);

// 结束播放加载动画
(() => {
setTimeout(() => {
document.getElementById("theme-color-loader-iframe").className = "end"; // 播放结束动画
document.body.style.paddingRight = "unset"; // 恢复 body 的右边距
document.body.style.overflow = "unset"; // 恢复显示滚动条
}, minimumColorSwitchTime);
})();
}
}

runScripts() {
// 遍历 <theme> 中的所有 <script> 标签
document.querySelectorAll("theme > script").forEach((script) => {
// 获取当前 script 标签的 src
const src = script.src;

// 如果 src 存在(确保它是一个外部链接)
if (src) {
// 移除原有的 script 标签
script.remove();

// 创建一个新的 script 标签并重新插入
const newScript = document.createElement("script");
newScript.src = src;
document.head.appendChild(newScript);
}
});
}
}

// 加载配色方案设置的选中效果
Expand Down
67 changes: 27 additions & 40 deletions assets/scripts/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global swal, marked */
/* global swal, markdownit */

// 获取网站配置
function getWebsiteConfig() {
Expand Down Expand Up @@ -26,6 +26,29 @@ function getWebsiteConfig() {
const config = getWebsiteConfig();
config.init();

// 对象递归初始化代理
function autoInitObject() {
return new Proxy({}, {
get(target, prop) {
// 如果属性不存在,则递归返回一个新的代理
if (!(prop in target)) {
target[prop] = autoInitObject();
}
return target[prop];
},
set(target, prop, value) {
// 正常设置属性
target[prop] = value;
return true;
}
});
}

// 初始化 markdown-it 实例
const md = new markdownit({
html: true // 允许 HTML 标签
});

// Markdown 渲染器
function renderMarkdown() {
// 获取页面中的所有 .markdown-content 元素
Expand All @@ -45,8 +68,8 @@ function renderMarkdown() {
return response.text();
})
.then((markdownContent) => {
// 使用 marked 库将 Markdown 转换为 HTML
const renderedHTML = marked.parse(markdownContent);
// 使用 markdown-it 库将 Markdown 转换为 HTML
const renderedHTML = md.render(markdownContent);

// 使用渲染后的 HTML 直接替换原始内容
element.innerHTML = renderedHTML;
Expand All @@ -61,41 +84,5 @@ function renderMarkdown() {
});
}

// 复制文本
function copy(data) {
let input = document.createElement("input");
input.setAttribute("readonly", "readonly");
input.value = data;
document.body.appendChild(input);
input.select();
document.execCommand("Copy");
document.body.removeChild(input);
swal("复制成功!");
}

// 显示邮箱
function showEmail() {
swal({
title: "E-mail",
text: "chengcheng@miao.ms",
buttons: ["复制", true],
}).then((OK) => {
if (OK) {
/* empty */
} else {
copy("chengcheng@miao.ms");
}
});
}

// 显示 URL
function showPageUrl() {
const url = window.location.href;
swal({
title: "URL",
text: url,
});
}

// 将方法挂载到全局对象 window
window.showEmail = showEmail;
window.autoInitObject = autoInitObject;
1 change: 1 addition & 0 deletions assets/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ body {

.page-head > .title,
.page-head > .typed-cursor {
height: max-content;
margin-top: 160px; /* [^1] 所以此处使用上边距实现居中,反正能跑就行( */
font-size: 32px;
font-weight: bold;
Expand Down
Loading

0 comments on commit cc25e84

Please sign in to comment.