├── .github └── dependabot.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── _config.yml ├── layout ├── archives.ejs ├── card.ejs ├── categories.ejs ├── comment.ejs ├── current.ejs ├── footer.ejs ├── import.ejs ├── index.ejs ├── layout.ejs ├── menu.ejs ├── post.ejs ├── posts.ejs └── tags.ejs ├── package.json ├── pnpm-lock.yaml └── source ├── css └── main.css ├── images └── loading.gif └── js ├── lib ├── crypto.js ├── highlight.js ├── home.js ├── math.js ├── preview.js └── search.js └── main.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Argvchs 4 | Copyright (c) 2020 korilin 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hexo-Theme-ParticleX 2 | 3 | [ParticleX](https://github.com/theme-particlex/hexo-theme-particlex) 主题,诞生原因是因为原来的 [Particle](https://github.com/korilin/hexo-theme-particle) 主题不维护了,但是我觉得还是很好的。 4 | 5 | 原来用的是 Vue 2 + Ant Design Vue 1,现更新到 Vue 3,去除 Ant Design Vue 采用自定义样式,图标更改为 Font Awesome 6,CDN 改为 ZStatic。 6 | 7 | 原项目 `README.md` 里说: 8 | 9 | > 目前有 Full、Night 和 Maiden **两个**主题样式。 10 | 11 | 但是更改后只有一种了,如果你想改颜色就在 `main.css` 里替换吧。 12 | 13 | # 1. 演示 14 | 15 | - [GitHub Pages](https://argvchs.github.io) 16 | - [Netlify](https://argvchs.netlify.app) 17 | - [Vercel](https://argvchs.vercel.app) 18 | 19 | # 2. 安装 20 | 21 | ```bash 22 | cd themes 23 | git clone https://github.com/theme-particlex/hexo-theme-particlex.git particlex --depth=1 24 | ``` 25 | 26 | 然后在根目录 `_config.yml` 设置主题为 ParticleX 即可。 27 | 28 | ```yaml 29 | theme: particlex 30 | ``` 31 | 32 | ## 2.1. 关闭自带代码高亮 33 | 34 | Hexo 有自带的代码高亮,但是和 ParticleX 的不兼容。 35 | 36 | ```yaml 37 | highlight: 38 | enable: false 39 | prismjs: 40 | enable: false 41 | ``` 42 | 43 | 如果使用 Hexo 7.0.0 之后的版本只需要修改为: 44 | 45 | ```yaml 46 | syntax_highlighter: 47 | ``` 48 | 49 | 如果使用 Pandoc 还需要设置一下: 50 | 51 | ```yaml 52 | pandoc: 53 | extra: 54 | - no-highlight: 55 | ``` 56 | 57 | ## 2.2. 禁用年度月度归档 58 | 59 | Hexo 会自动生成年度月度归档,可是 ParticleX 主题没有这个功能。~~我太懒了~~ 60 | 61 | ```yaml 62 | archive_generator: 63 | enabled: true 64 | per_page: 0 65 | yearly: false 66 | monthly: false 67 | daily: false 68 | ``` 69 | 70 | 修改完请 `hexo cl` 清除缓存。 71 | 72 | # 3. 配置 73 | 74 | ## 3.1. 基本配置 75 | 76 | `background` 参数是一个列表,打开时会随机加载一个背景。 77 | 78 | ```yaml 79 | # Avatar image 80 | avatar: /images/avatar.jpg 81 | 82 | # Home page background image 83 | background: 84 | - /images/background.jpg 85 | 86 | # Loading image 87 | loading: /images/loading.gif 88 | 89 | # Optional colors for category and tag 90 | colors: 91 | - "#ffa2c4" 92 | - "#00bcd4" 93 | - "#03a9f4" 94 | - "#00a596" 95 | - "#ff7d73" 96 | ``` 97 | 98 | ## 3.2. 内容配置 99 | 100 | ### 3.2.1. 导航栏 101 | 102 | 为了方便,主题使用的图标是 Font Awesome 6 图标。 103 | 104 | ```yaml 105 | # ParticleX theme icon is adopts the Font Awesome 6 106 | # https://fontawesome.com 107 | 108 | # Main menu navigation 109 | menu: 110 | Home: 111 | name: house 112 | theme: solid 113 | link: / 114 | About: 115 | name: id-card 116 | theme: solid 117 | link: /about 118 | Archives: 119 | name: box-archive 120 | theme: solid 121 | link: /archives 122 | Categories: 123 | name: bookmark 124 | theme: solid 125 | link: /categories 126 | Tags: 127 | name: tags 128 | theme: solid 129 | link: /tags 130 | ``` 131 | 132 | ### 3.2.2. 主页信息卡片 133 | 134 | `description` 支持 Markdown 格式。 135 | 136 | 图标链接 `iconLinks` 配置和导航栏配置相同。 137 | 138 | ```yaml 139 | # Side info card 140 | card: 141 | enable: true 142 | description: | 143 | Description 144 | ... 145 | iconLinks: 146 | friendLinks: 147 | Argvchs: https://argvchs.github.io 148 | ``` 149 | 150 | ### 3.2.3. 页脚 151 | 152 | 考虑到博客部署在服务器并使用自己域名的情况,按规定需要在网站下边添加备案消息。 153 | 154 | 如没有需要显示备案消息的可以关闭。 155 | 156 | ```yaml 157 | # Footer info 158 | footer: 159 | since: 2022 160 | # Customize the server domain name ICP 161 | ICP: 162 | enable: false 163 | code: 164 | link: 165 | ``` 166 | 167 | ## 3.3. 功能配置 168 | 169 | ### 3.3.1. Polyfill 170 | 171 | 使用 [Polyfill.io](https://polyfill.io) 自动根据 UA 处理新的 JS API 兼容。 172 | 173 | 可以配合 [Hexo-Babel](https://github.com/theme-particlex/hexo-babel) 插件处理 JS 语法兼容。 174 | 175 | Polyfill 在国内一些省份被墙,这里换成了阿里的 [Polyfill](https://polyfill.alicdn.com)。 176 | 177 | ```yaml 178 | # Polyfill 179 | # https://polyfill.io 180 | polyfill: 181 | enable: true 182 | features: 183 | - default 184 | ``` 185 | 186 | ### 3.3.2. 代码高亮 187 | 188 | 使用 Highlight.js 代码高亮。 189 | 190 | 样式可以在[这里](https://highlightjs.org/static/demo)选择,默认为 GitHub。 191 | 192 | ```yaml 193 | # Highlight.js 194 | # https://highlightjs.org 195 | highlight: 196 | enable: true 197 | style: github 198 | ``` 199 | 200 | ### 3.3.3. 数学渲染 201 | 202 | 使用 KaTeX 渲染数学公式。 203 | 204 | ```yaml 205 | # KaTeX math rendering 206 | math: 207 | enable: false 208 | ``` 209 | 210 | ### 3.3.4. 图片预览 211 | 212 | 简单的点击图片放大缩小的预览。 213 | 214 | ```yaml 215 | # Image preview 216 | preview: 217 | enable: true 218 | ``` 219 | 220 | ### 3.3.5. 文章缩略 221 | 222 | 一般来说,缩略展示文档只需要在文档中添加 `` 即可,缩略内容在显示全文中也会出现。 223 | 224 | 但考虑到不想把缩略内容放在正文里,就添加了此参数,在 [Front-Matter](https://hexo.io/docs/front-matter) 里设置。 225 | 226 | 支持 Markdown 格式。 227 | 228 | ```yaml 229 | description: | 230 | Normal _Italic_ **Strong** 231 | ``` 232 | 233 | ### 3.3.6. 文章置顶 234 | 235 | 在 [Front-Matter](https://hexo.io/docs/front-matter) 里设置 `pinned` 作为置顶参数,越大越靠前,默认为 0。 236 | 237 | ### 3.3.7. 文章加密 238 | 239 | 使用 AES 加密算法,在 [Front-Matter](https://hexo.io/docs/front-matter) 里设置 `secret` 作为密码,**使用请安装插件 [Hexo-Helper-Crypto](https://github.com/theme-particlex/hexo-helper-crypto)**。 240 | 241 | ```yaml 242 | # Article encryption 243 | crypto: 244 | enable: false 245 | ``` 246 | 247 | ### 3.3.8. 搜索 248 | 249 | 嵌入到 Archives 中的搜索。 250 | 251 | 目前只支持搜索文档标题。 252 | 253 | ```yaml 254 | # Search 255 | search: 256 | enable: false 257 | ``` 258 | 259 | ## 3.4. 评论配置 260 | 261 | ### 3.4.1. giscus 262 | 263 | giscus 是一个由 GitHub Discussions 支持的评论系统。 264 | 265 | 在 [giscus.app](https://giscus.app) 设置好各项后,会在下面生成一个 ` 18 | <% } %> 19 | <% if (theme.gitalk.enable) { %> 20 | 35 | <% } %> 36 | <% if (theme.waline.enable) { %> 37 | 55 | <% } %> 56 | <% if (theme.twikoo.enable) { %> 57 | 66 | <% } %> 67 | -------------------------------------------------------------------------------- /layout/current.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (page.current !== 1) { %> 3 | 4 | 5 | 6 | 1 7 | ... 8 | <% } %> 9 | <%= page.current %> 10 | <% if (page.current + 1 <= page.total) { %> 11 | "> 12 | <%= page.current + 1 %> 13 | 14 | <% } %> 15 | <% if (page.current + 2 <= page.total) { %> 16 | "> 17 | <%= page.current + 2 %> 18 | 19 | <% } %> 20 | <% if (page.current + 3 <= page.total) { %> 21 | ... 22 | "><%= page.total %> 23 | <% } %> 24 | <% if (page.current !== page.total) { %> 25 | 26 | 27 | 28 | <% } %> 29 |
30 | -------------------------------------------------------------------------------- /layout/footer.ejs: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /layout/import.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | <% if (theme.polyfill.enable) { %> 12 | 13 | <% } %> 14 | <% if (theme.highlight.enable) { %> 15 | 16 | 17 | 21 | 22 | <% } %> 23 | <% if (theme.math.enable) { %> 24 | 25 | 26 | 27 | 28 | <% } %> 29 | <% if (theme.preview.enable) { %> 30 | 31 | <% } %> 32 | <% if (theme.crypto.enable && typeof page.secret !== "undefined") { %> 33 | 34 | 35 | <% } %> 36 | <% if (type === "archives" && theme.search.enable) { %> 37 | 38 | <% } %> 39 | <% if (type === "post" && page.comments) { %> 40 | <% if (theme.gitalk.enable) { %> 41 | 42 | 43 | <% } %> 44 | <% if (theme.waline.enable) { %> 45 | 46 | 47 | 48 | <% } %> 49 | <% if (theme.twikoo.enable) { %> 50 | 51 | <% } %> 52 | <% } %> 53 | <% if (type === "index") { %> 54 | 55 | <% } %> 56 | 57 | " /> 58 | 59 | -------------------------------------------------------------------------------- /layout/index.ejs: -------------------------------------------------------------------------------- 1 |
2 |
7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 |

<%= config.title %>

15 |

<%= config.subtitle %>

16 |
<%= config.description %>
17 |
18 |
19 |
20 |
21 |
25 | > 26 |
27 | <%- partial("posts") %> 28 | <%- partial("current") %> 29 |
30 | <% if (theme.card.enable) { %> 31 |
32 | <%- partial("card") %> 33 |
34 | <% } %> 35 |
36 | -------------------------------------------------------------------------------- /layout/layout.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | let type = "post"; 3 | if (is_home()) type = "index"; 4 | if (is_post() || is_page()) type = "post"; 5 | if (is_category() || page.type === "categories") type = "categories"; 6 | if (is_tag() || page.type === "tags") type = "tags"; 7 | if (is_archive()) type = "archives"; 8 | let title = page.title + " | " + config.title; 9 | if (is_home()) title = config.title; 10 | if (is_post() || is_page()) title = page.title + " | " + config.title; 11 | if (is_category()) title = "Categories: " + page.category + " | " + config.title; 12 | if (is_tag()) title = "Tags: " + page.tag + " | " + config.title; 13 | if (is_archive()) title = "Archives | " + config.title; 14 | %> 15 | 16 | 17 | 18 | 19 | <%= title %> 20 | 21 | 22 | 23 | 27 | 28 | <%- partial("import", { type }) %> 29 | 30 | 31 |
32 | 33 |
34 |
35 |

LOADING

36 |

加载过慢请开启缓存 浏览器默认开启

37 | 38 |
39 |
40 |
41 | <%- partial("menu") %> 42 |
43 | <%- partial(type) %> 44 | <%- partial("footer") %> 45 |
46 | <% if (theme.preview.enable) { %> 47 | 48 |
49 | 50 |
51 |
52 | <% } %> 53 |
54 | 55 | 62 | <% if (type === "post" && page.comments) { %> 63 | <%- partial("comment") %> 64 | <% } %> 65 | 66 | 67 | -------------------------------------------------------------------------------- /layout/menu.ejs: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /layout/post.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= page.title %>

4 |
5 |
6 | 7 | 8 | 9 | 10 | <%= date(page.date, "YYYY/M/D") %> 11 | 12 | <% if (page.categories && page.categories.data.length !== 0) { %> 13 | 14 | 15 | 16 | 17 | 18 | <%= page.categories.data[0].name %> 19 | 20 | 21 | <% } %> 22 | <% if (page.tags && page.tags.data.length !== 0) { %> 23 | 24 | 25 | 26 | 27 | <% let prev; %> 28 | <% page.tags.data.forEach((tag) => { %> 29 | 30 | <% 31 | const colors = theme.colors.filter((color) => color !== prev); 32 | let id = Math.floor(Math.random() * colors.length); 33 | prev = colors[id]; 34 | %> 35 | 36 | <%= tag.name %> 37 | 38 | 39 | <% }); %> 40 | 41 | <% } %> 42 |
43 | <% if (theme.crypto.enable && typeof page.secret !== "undefined") { %> 44 | <% const CryptoJS = getCryptoJS(); %> 45 | 55 | 56 |
57 |
58 | <% } else { %> 59 |
60 | <%- page.content %> 61 |
62 | <% } %> 63 | <% if (page.comments) { %> 64 | <% if (theme.gitalk.enable) { %> 65 |
66 |
67 |
68 | <% } %> 69 | <% if (theme.giscus.enable) { %> 70 |
71 |
72 |
73 | <% } %> 74 | <% if (theme.waline.enable) { %> 75 |
76 |
77 |
78 | <% } %> 79 | <% if (theme.twikoo.enable) { %> 80 |
81 |
82 |
83 | <% } %> 84 | <% } %> 85 |
86 | -------------------------------------------------------------------------------- /layout/posts.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | let posts = site.posts, 3 | current = (page.current - 1) * config.index_generator.per_page; 4 | posts.data.sort((a, b) => { 5 | let x = a.pinned ?? 0, 6 | y = b.pinned ?? 0; 7 | return x === y ? b.date - a.date : y - x; 8 | }); 9 | posts = posts.slice(current, config.index_generator.per_page + current); 10 | %> 11 | <% posts.forEach((post) => { %> 12 |
13 | 14 |

<%= post.title %>

15 |
16 |
17 | <% if (post.categories.data.length !== 0) { %> 18 | 19 | 20 | 21 | 22 | 23 | <%= post.categories.data[0].name %> 24 | 25 | 26 | <% } %> 27 | 28 | 29 | 30 | 31 | <%- date(post.date, "YYYY/M/D") %> 32 | 33 | <% if (theme.crypto.enable && typeof post.secret !== "undefined") { %> 34 | 35 | 36 | 37 | <% } %> 38 | <% if (typeof post.pinned !== "undefined") { %> 39 | 40 | 41 | 42 | <% } %> 43 |
44 |
45 |
46 | <% if (typeof post.description !== "undefined") { %> 47 | <%- markdown(post.description) %> 48 | <% } else if (post.excerpt) { %> 49 | <%- post.excerpt %> 50 | <% } else { %> 51 | <%- post.content %> 52 | <% } %> 53 |
54 |
55 |
56 | <% if (post.tags.data.length !== 0) { %> 57 | 58 | 59 | 60 | <% } %> 61 | <% let prev; %> 62 | <% post.tags.data.forEach((tag) => { %> 63 | 64 | <% 65 | const colors = theme.colors.filter((color) => color !== prev); 66 | let id = Math.floor(Math.random() * colors.length); 67 | prev = colors[id]; 68 | %> 69 | <%= tag.name %> 70 | 71 | <% }); %> 72 |
73 | 阅读全文 74 |
75 | <% }); %> 76 | -------------------------------------------------------------------------------- /layout/tags.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% let posts = []; %> 3 |
4 | <% let prev; %> 5 | <% site.tags.forEach((tag) => { %> 6 | <% 7 | const colors = is_tag(tag.name) 8 | ? ["linear-gradient(120deg, #9abbf7 0%, #ffbbf4 100%)"] 9 | : theme.colors.filter((color) => color !== prev); 10 | let id = Math.floor(Math.random() * colors.length); 11 | prev = colors[id]; 12 | %> 13 | 14 | 15 | 16 | 17 | 18 | <%= tag.name %> 19 | 20 | 21 | <% if (is_tag(tag.name)) { %> 22 | <% 23 | posts = tag.posts; 24 | posts.data.sort((a, b) => b.date - a.date); 25 | %> 26 | <% } %> 27 | <% }); %> 28 |
29 | <% posts.forEach((post) => { %> 30 |
31 |
32 |
33 |
<%= date(post.date, "YYYY/M/D") %>
34 | 35 |

<%= post.title %>

36 |
37 |
38 | <% if (post.categories && post.categories.data.length !== 0) { %> 39 | 40 | 41 | 42 | 43 | 44 | <%= post.categories.data[0].name %> 45 | 46 | 47 | <% } %> 48 | <% if (post.tags && post.tags.data.length !== 0) { %> 49 | 50 | 51 | 52 | 53 | <% let prev; %> 54 | <% post.tags.data.forEach((tag) => { %> 55 | 56 | <% 57 | const colors = theme.colors.filter((color) => color !== prev); 58 | let id = Math.floor(Math.random() * colors.length); 59 | prev = colors[id]; 60 | %> 61 | 62 | <%= tag.name %> 63 | 64 | 65 | <% }); %> 66 | 67 | <% } %> 68 |
69 |
70 |
71 | <% }); %> 72 |
73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-theme-particlex", 3 | "version": "2.8.1", 4 | "description": "A concise Hexo theme, based on Particle.", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/theme-particlex/hexo-theme-particlex.git" 11 | }, 12 | "keywords": [ 13 | "hexo", 14 | "hexo-theme", 15 | "gitalk", 16 | "twikoo", 17 | "waline", 18 | "giscus" 19 | ], 20 | "author": "Argvchs", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/theme-particlex/hexo-theme-particlex/issues" 24 | }, 25 | "homepage": "https://github.com/theme-particlex/hexo-theme-particlex#readme", 26 | "dependencies": { 27 | "hexo-helper-crypto": "^1.2.1", 28 | "hexo-renderer-ejs": "^2.0.0" 29 | }, 30 | "packageManager": "pnpm@9.7.0+sha512.dc09430156b427f5ecfc79888899e1c39d2d690f004be70e05230b72cb173d96839587545d09429b55ac3c429c801b4dc3c0e002f653830a420fa2dd4e3cf9cf" 31 | } 32 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | hexo-helper-crypto: 12 | specifier: ^1.2.1 13 | version: 1.2.1 14 | hexo-renderer-ejs: 15 | specifier: ^2.0.0 16 | version: 2.0.0 17 | 18 | packages: 19 | 20 | ansi-styles@4.3.0: 21 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 22 | engines: {node: '>=8'} 23 | 24 | async@3.2.5: 25 | resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} 26 | 27 | balanced-match@1.0.2: 28 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 29 | 30 | brace-expansion@1.1.11: 31 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 32 | 33 | brace-expansion@2.0.1: 34 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 35 | 36 | chalk@4.1.2: 37 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 38 | engines: {node: '>=10'} 39 | 40 | color-convert@2.0.1: 41 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 42 | engines: {node: '>=7.0.0'} 43 | 44 | color-name@1.1.4: 45 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 46 | 47 | concat-map@0.0.1: 48 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 49 | 50 | crypto-js@4.2.0: 51 | resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} 52 | 53 | ejs@3.1.10: 54 | resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} 55 | engines: {node: '>=0.10.0'} 56 | hasBin: true 57 | 58 | filelist@1.0.4: 59 | resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} 60 | 61 | has-flag@4.0.0: 62 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 63 | engines: {node: '>=8'} 64 | 65 | hexo-helper-crypto@1.2.1: 66 | resolution: {integrity: sha512-xkqXiP/BH2zCcAVs9PWwh5NdXRW/oeXZr/5R/NTyGa262a7RJdGYo7Ead2b8T98k5fOydCPzoOirK/tufKmdtQ==} 67 | 68 | hexo-renderer-ejs@2.0.0: 69 | resolution: {integrity: sha512-qCjE1IdwgDgv65qyb0KMVCwCdSVAkH0vwAe9XihjvaKWkmb9dtt8DgErOdqCXn0HReSyWiEVP2BrLRj3gyHwOQ==} 70 | engines: {node: '>=12'} 71 | 72 | jake@10.9.2: 73 | resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} 74 | engines: {node: '>=10'} 75 | hasBin: true 76 | 77 | minimatch@3.1.2: 78 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 79 | 80 | minimatch@5.1.6: 81 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 82 | engines: {node: '>=10'} 83 | 84 | supports-color@7.2.0: 85 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 86 | engines: {node: '>=8'} 87 | 88 | snapshots: 89 | 90 | ansi-styles@4.3.0: 91 | dependencies: 92 | color-convert: 2.0.1 93 | 94 | async@3.2.5: {} 95 | 96 | balanced-match@1.0.2: {} 97 | 98 | brace-expansion@1.1.11: 99 | dependencies: 100 | balanced-match: 1.0.2 101 | concat-map: 0.0.1 102 | 103 | brace-expansion@2.0.1: 104 | dependencies: 105 | balanced-match: 1.0.2 106 | 107 | chalk@4.1.2: 108 | dependencies: 109 | ansi-styles: 4.3.0 110 | supports-color: 7.2.0 111 | 112 | color-convert@2.0.1: 113 | dependencies: 114 | color-name: 1.1.4 115 | 116 | color-name@1.1.4: {} 117 | 118 | concat-map@0.0.1: {} 119 | 120 | crypto-js@4.2.0: {} 121 | 122 | ejs@3.1.10: 123 | dependencies: 124 | jake: 10.9.2 125 | 126 | filelist@1.0.4: 127 | dependencies: 128 | minimatch: 5.1.6 129 | 130 | has-flag@4.0.0: {} 131 | 132 | hexo-helper-crypto@1.2.1: 133 | dependencies: 134 | crypto-js: 4.2.0 135 | 136 | hexo-renderer-ejs@2.0.0: 137 | dependencies: 138 | ejs: 3.1.10 139 | 140 | jake@10.9.2: 141 | dependencies: 142 | async: 3.2.5 143 | chalk: 4.1.2 144 | filelist: 1.0.4 145 | minimatch: 3.1.2 146 | 147 | minimatch@3.1.2: 148 | dependencies: 149 | brace-expansion: 1.1.11 150 | 151 | minimatch@5.1.6: 152 | dependencies: 153 | brace-expansion: 2.0.1 154 | 155 | supports-color@7.2.0: 156 | dependencies: 157 | has-flag: 4.0.0 158 | -------------------------------------------------------------------------------- /source/css/main.css: -------------------------------------------------------------------------------- 1 | #archives { 2 | margin: auto; 3 | margin-top: 100px; 4 | padding: 20px; 5 | } 6 | #archives .categories-tags { 7 | margin: auto; 8 | margin-bottom: 50px; 9 | max-width: 900px; 10 | text-align: center; 11 | width: 100%; 12 | } 13 | #archives .categories-tags span { 14 | display: inline-block; 15 | margin: 10px; 16 | } 17 | #archives .categories-tags span .icon { 18 | color: #fff; 19 | margin-left: 0; 20 | margin-right: 10px; 21 | } 22 | #archives .categories-tags span a { 23 | border: #ffffff80 1px solid; 24 | border-radius: 10px; 25 | color: #fff; 26 | padding: 10px 15px; 27 | transition: background 0.25s, border 0.25s, color 0.25s; 28 | } 29 | #archives .categories-tags span a:hover { 30 | background: #fff !important; 31 | border: #a5c2f5 1px solid; 32 | color: #5c6b72; 33 | } 34 | #archives .category, 35 | #archives .tags .tag, 36 | .article .info .category, 37 | .article .info .tags, 38 | .article .info .tags .tag { 39 | display: inline-block; 40 | margin-right: 10px; 41 | } 42 | #archives h3 { 43 | margin: 10px 0; 44 | } 45 | #crypto { 46 | margin: 50px 0; 47 | } 48 | #crypto.failure { 49 | border-color: #ea4a5a; 50 | color: #ea4a5a; 51 | } 52 | #crypto.failure:focus { 53 | box-shadow: 0 0 0 3px #ea4a5a4d; 54 | } 55 | #crypto.success { 56 | border-color: #34d058; 57 | color: #34d058; 58 | } 59 | #footer { 60 | font-size: 14px; 61 | margin-top: 150px; 62 | padding-bottom: 20px; 63 | text-align: center; 64 | width: 100%; 65 | } 66 | #footer #footer-icon { 67 | color: #66afef; 68 | display: inline-block; 69 | font-size: 18px; 70 | margin: 0 10px; 71 | } 72 | #footer #footer-wrap { 73 | border-top: 1px solid #aaa; 74 | color: #5c6b72; 75 | margin: auto; 76 | width: 900px; 77 | } 78 | #footer #footer-wrap div { 79 | margin: 15px; 80 | } 81 | #home-card { 82 | width: 300px; 83 | } 84 | #home-card #card-style { 85 | background: #fff; 86 | border: none; 87 | border-radius: 10px; 88 | box-shadow: 0 0 20px #d9d9d980; 89 | display: flex; 90 | flex-direction: column; 91 | max-height: 80vh; 92 | justify-content: center; 93 | overflow: auto; 94 | position: sticky; 95 | text-align: center; 96 | top: 10vh; 97 | width: 300px; 98 | } 99 | #home-card #card-div { 100 | overflow: auto; 101 | padding: 25px 0; 102 | } 103 | #home-card #card-div .avatar { 104 | border: #f1f1f1 solid 3px; 105 | border-radius: 50%; 106 | height: 140px; 107 | margin: auto; 108 | text-align: center; 109 | width: 140px; 110 | } 111 | #home-card #card-div .avatar img { 112 | border-radius: 50%; 113 | height: 100%; 114 | width: 100%; 115 | } 116 | #home-card #card-div .avatar:hover img { 117 | transform: rotate(360deg); 118 | } 119 | #home-card #card-div .description { 120 | margin: 20px auto; 121 | width: 85%; 122 | } 123 | #home-card #card-div .friend-links .friend-link { 124 | margin-bottom: 5px; 125 | } 126 | #home-card #card-div .friend-links a { 127 | border-radius: 5px; 128 | color: #5c6b72; 129 | display: block; 130 | padding: 8px 0; 131 | } 132 | #home-card #card-div .icon-links .icon-link { 133 | margin: 5px; 134 | } 135 | #home-card #card-div .icon-links a { 136 | border-radius: 5px; 137 | color: #5c6b72; 138 | font-size: 18px; 139 | padding: 5px; 140 | } 141 | #home-card #card-div .icon-links a:hover, 142 | #home-card #card-div .friend-links a:hover, 143 | #home-posts .page-current .page-num:hover { 144 | background: #66afef; 145 | color: #fff; 146 | } 147 | #home-card #card-div .icon-links, 148 | #home-card #card-div .friend-links { 149 | border-top: #cdcdcd solid 1px; 150 | margin: 10px auto; 151 | padding-top: 10px; 152 | width: 85%; 153 | } 154 | #home-card #card-div .name { 155 | font-size: 16px; 156 | font-weight: bold; 157 | margin: 20px auto; 158 | } 159 | #home-head { 160 | display: flex; 161 | height: 100vh; 162 | width: 100vw; 163 | } 164 | #home-head #home-background { 165 | background-position: center; 166 | background-repeat: no-repeat; 167 | background-size: cover; 168 | height: 100vh; 169 | left: 0; 170 | position: absolute; 171 | top: 0; 172 | width: 100vw; 173 | z-index: -1; 174 | } 175 | #home-head #home-info .info { 176 | align-items: center; 177 | border-radius: 50%; 178 | display: flex; 179 | justify-content: center; 180 | text-align: center; 181 | } 182 | #home-head #home-info .loop:nth-child(1) { 183 | animation: loop1 10s linear infinite; 184 | background: #fff; 185 | border-radius: 38% 62% 63% 37%/41% 44% 56% 59%; 186 | opacity: 0.3; 187 | transform: rotate(30deg); 188 | } 189 | #home-head #home-info .loop:nth-child(2) { 190 | animation: loop2 15s linear infinite; 191 | background: #fff; 192 | border-radius: 38% 62% 63% 37%/41% 44% 56% 59%; 193 | opacity: 0.45; 194 | transform: rotate(60deg); 195 | } 196 | #home-head #home-info .loop:nth-child(3) { 197 | animation: loop3 10s linear infinite; 198 | background: #fff; 199 | border-radius: 38% 62% 63% 37%/41% 44% 56% 59%; 200 | opacity: 0.3; 201 | transform: rotate(90deg); 202 | } 203 | #home-head #home-info .loop:nth-child(4) { 204 | animation: loop4 15s linear infinite; 205 | background: #fff; 206 | border-radius: 38% 62% 63% 37%/41% 44% 56% 59%; 207 | opacity: 0.45; 208 | transform: rotate(120deg); 209 | } 210 | #home-head #home-info, 211 | #home-posts { 212 | margin: auto; 213 | } 214 | #home-posts .page-current { 215 | align-items: center; 216 | display: flex; 217 | font-weight: bold; 218 | justify-content: center; 219 | margin-top: 50px; 220 | text-align: center; 221 | width: 100%; 222 | } 223 | #home-posts .page-current .current { 224 | border-radius: 5px; 225 | color: #da0a51; 226 | display: inline-block; 227 | height: 35px; 228 | line-height: 35px; 229 | margin: 0 7px; 230 | padding: 5px; 231 | width: 35px; 232 | } 233 | #home-posts .page-current .page-num, 234 | #home-posts .page-current .page-omit { 235 | border-radius: 5px; 236 | display: inline-block; 237 | height: 35px; 238 | line-height: 35px; 239 | margin: 0 7px; 240 | padding: 5px; 241 | width: 35px; 242 | } 243 | #home-posts .page-current a { 244 | color: #999; 245 | } 246 | #home-posts .post { 247 | background: #fff; 248 | border-radius: 20px; 249 | box-shadow: 0 0 20px #d9d9d980; 250 | transition: box-shadow 0.25s, transform 0.25s; 251 | } 252 | #home-posts .post .category-and-date { 253 | color: #5c6b72; 254 | margin-top: 15px; 255 | text-align: center; 256 | width: 100%; 257 | } 258 | #home-posts .post .category-and-date .category { 259 | display: inline-block; 260 | margin-right: 25px; 261 | } 262 | #home-posts .post .category-and-date .category a, 263 | #archives a, 264 | #archives .tag-icon, 265 | #archives .item-time, 266 | #archives .categories-tags span a:hover .icon, 267 | .article .info a { 268 | color: #5c6b72; 269 | } 270 | #home-posts .post .category-and-date .date, 271 | #archives .tags, 272 | #menu #desktop-menu a span { 273 | display: inline-block; 274 | } 275 | #home-posts .post .category-and-date .special { 276 | display: inline-block; 277 | margin-left: 25px; 278 | } 279 | #home-posts .post .go-post { 280 | background: linear-gradient(120deg, #9abbf7 0%, #ffbbf4 100%); 281 | border: 0; 282 | border-radius: 20px 0; 283 | bottom: -5px; 284 | box-shadow: 2px 2px 10px 0 #ffbbf47a; 285 | color: #fff; 286 | font-size: 14px; 287 | font-weight: bold; 288 | padding: 10px 24px; 289 | position: absolute; 290 | right: -5px; 291 | transition: box-shadow 0.25s ease-out, right 0.25s ease-out; 292 | } 293 | #home-posts .post .go-post:hover { 294 | box-shadow: -2px -2px 10px 0 #9abbf77a; 295 | right: -7px; 296 | } 297 | #home-posts .post .post-tags .tag { 298 | display: inline-block; 299 | font-weight: bold; 300 | margin-right: 10px; 301 | } 302 | #home-posts .post .post-tags a { 303 | font-size: 14px; 304 | } 305 | #home-posts .post .post-tags, 306 | #archives .info, 307 | .article .info { 308 | line-height: 1.7; 309 | } 310 | #home-posts .post-title { 311 | color: #66afef; 312 | text-align: center; 313 | } 314 | #home-posts .post:hover { 315 | box-shadow: 0 0 5px #d9d9d9; 316 | transform: translate(-5px, -5px); 317 | } 318 | #home-posts-wrap { 319 | background: transparent; 320 | border-radius: 10px; 321 | display: flex; 322 | margin: auto; 323 | padding: 20px; 324 | } 325 | #home-posts-wrap, 326 | #archives, 327 | .article, 328 | #footer #footer-wrap { 329 | box-sizing: border-box; 330 | } 331 | #loading { 332 | align-items: center; 333 | background: #fff; 334 | display: flex; 335 | flex-direction: column; 336 | height: 100vh; 337 | justify-content: center; 338 | left: 0; 339 | position: fixed; 340 | top: 0; 341 | width: 100vw; 342 | word-break: keep-all; 343 | z-index: 2147483647; 344 | } 345 | #loading h2, 346 | #loading p, 347 | #loading img { 348 | margin: 10px; 349 | } 350 | #loading img { 351 | border-radius: 0; 352 | height: 50px; 353 | } 354 | #loading-circle { 355 | align-items: center; 356 | border: 10px solid #a3ddfb; 357 | border-radius: 50%; 358 | display: flex; 359 | flex-direction: column; 360 | height: 50vmin; 361 | justify-content: center; 362 | padding: 50px; 363 | text-align: center; 364 | width: 50vmin; 365 | } 366 | #main { 367 | margin-right: calc(100% - 100vw); 368 | } 369 | #menu { 370 | background: #92cafa; 371 | box-shadow: 0 -1px 10px 0 #9e9e9e4d; 372 | font-weight: bold; 373 | line-height: 50px; 374 | position: fixed; 375 | top: 0; 376 | transition: background 0.25s ease-out, top 0.25s ease-out; 377 | width: 100vw; 378 | z-index: 1004; 379 | } 380 | #menu #desktop-menu { 381 | height: 50px; 382 | } 383 | #menu #desktop-menu .title { 384 | color: #555; 385 | display: inline-block; 386 | margin-left: 60px; 387 | margin-right: 5px; 388 | } 389 | #menu #desktop-menu a { 390 | color: #555; 391 | display: inline-block; 392 | margin-left: 30px; 393 | } 394 | #menu #mobile-menu { 395 | min-height: 50px; 396 | text-align: center; 397 | } 398 | #menu #mobile-menu .items { 399 | padding: 10px 0 20px; 400 | z-index: 1002; 401 | } 402 | #menu #mobile-menu .items .item { 403 | display: flex; 404 | justify-content: center; 405 | margin: auto; 406 | min-width: 200px; 407 | width: 80%; 408 | } 409 | #menu #mobile-menu .items a { 410 | color: #555; 411 | } 412 | #menu #mobile-menu .title { 413 | color: #555; 414 | cursor: pointer; 415 | z-index: 1003; 416 | } 417 | #menu-curtain { 418 | background: #0003; 419 | height: 100%; 420 | left: 0; 421 | position: fixed; 422 | top: 0; 423 | width: 100%; 424 | z-index: 1001; 425 | } 426 | #menu.hidden { 427 | top: -50px; 428 | } 429 | #menu.menu-color { 430 | background: #0003; 431 | } 432 | #menu.menu-color #desktop-menu a, 433 | #menu.menu-color #mobile-menu a, 434 | #menu.menu-color #mobile-menu .title { 435 | color: #fff; 436 | } 437 | #preview { 438 | align-items: center; 439 | background-color: #fffc; 440 | display: flex; 441 | height: 100vh; 442 | justify-content: center; 443 | left: 0; 444 | position: fixed; 445 | top: 0; 446 | width: 100vw; 447 | z-index: 1005; 448 | } 449 | #preview-content { 450 | box-shadow: 0 0 50px 10px #d9d9d980; 451 | margin: auto; 452 | max-height: 95%; 453 | max-width: 95%; 454 | } 455 | #search-bar { 456 | margin-bottom: 50px; 457 | z-index: 1000; 458 | } 459 | #timeline-wrap { 460 | display: flex; 461 | flex-direction: column-reverse; 462 | } 463 | * { 464 | margin: 0; 465 | padding: 0; 466 | position: relative; 467 | scrollbar-color: #8ab5ff #e6efff; 468 | scrollbar-width: thin; 469 | word-wrap: break-word; 470 | } 471 | .article { 472 | font-size: 15px; 473 | margin: auto; 474 | margin-top: 100px; 475 | padding: 20px; 476 | } 477 | .article .content { 478 | margin: 50px 0; 479 | } 480 | .article .info .date { 481 | color: #5c6b72; 482 | display: inline-block; 483 | margin-right: 10px; 484 | } 485 | .code-content { 486 | font-size: 13px; 487 | line-height: 2; 488 | overflow: auto; 489 | padding: 50px 30px 20px; 490 | white-space: pre; 491 | } 492 | .comment iframe, 493 | body::-webkit-scrollbar-track { 494 | border-radius: 0; 495 | } 496 | .content { 497 | transition: opacity 0.25s; 498 | } 499 | .content img, 500 | .content video, 501 | .content audio, 502 | .content iframe { 503 | display: block; 504 | margin: 15px auto; 505 | max-width: 75%; 506 | } 507 | .copycode { 508 | color: #5c6b72; 509 | position: absolute; 510 | right: 0; 511 | top: 0; 512 | } 513 | .copycode i { 514 | padding: 15px; 515 | position: absolute; 516 | right: 0; 517 | top: 0; 518 | transition: transform 0.25s; 519 | } 520 | .copycode.copied i { 521 | transform: scale(1.25); 522 | } 523 | .copycode.copied i:first-child, 524 | .copycode:not(.copied) i:last-child { 525 | opacity: 0; 526 | } 527 | .fade-enter-active, 528 | .fade-leave-active { 529 | transition: opacity 0.3s; 530 | } 531 | .fade-enter-from, 532 | .fade-leave-to { 533 | opacity: 0; 534 | } 535 | .hljs-ln-code { 536 | padding-left: 20px !important; 537 | } 538 | .hljs-ln-numbers { 539 | border-right: 1px solid #ccc; 540 | color: #ccc; 541 | padding-right: 10px !important; 542 | text-align: right; 543 | vertical-align: top; 544 | } 545 | .icon { 546 | color: #5c6b72; 547 | margin-right: 5px; 548 | } 549 | .input { 550 | background: #f6f8fa; 551 | border: 1px solid #d0d7de; 552 | border-radius: 50px; 553 | box-sizing: border-box; 554 | color: #000; 555 | display: block; 556 | font-size: 15px; 557 | height: 50px; 558 | text-indent: 20px; 559 | transition: background 0.25s, border 0.25s, box-shadow 0.25s; 560 | width: 100%; 561 | } 562 | .input:focus { 563 | background: #fff; 564 | border-color: #0969da; 565 | box-shadow: 0 0 0 3px #0969da4d; 566 | outline: none; 567 | } 568 | .input:hover { 569 | background: #fff; 570 | } 571 | .into-enter-active { 572 | transition: opacity 0.5s, transform 0.5s; 573 | } 574 | .into-enter-from { 575 | opacity: 0; 576 | transform: scale(1.1); 577 | } 578 | .katex { 579 | white-space: normal !important; 580 | } 581 | .language { 582 | background: linear-gradient(to right, #ed6ea0 0%, #ec8c69 100%); 583 | border-radius: 0 0 10px 10px; 584 | box-shadow: 1px 1px 0.75rem #ed6ea14d; 585 | color: #fff; 586 | font-size: 12px; 587 | font-weight: bold; 588 | left: 30px; 589 | padding: 10px 15px; 590 | position: absolute; 591 | top: 0; 592 | } 593 | .page-num, 594 | .icon-link a, 595 | .friend-link a { 596 | transition: background 0.25s, color 0.25s; 597 | } 598 | .page-num:hover, 599 | .icon-link a:hover, 600 | .friend-link a:hover, 601 | .categories-tags a:hover, 602 | .go-post:hover { 603 | opacity: 1; 604 | } 605 | .slide-enter-active, 606 | .slide-leave-active { 607 | transition: margin-top 0.3s, opacity 0.3s; 608 | } 609 | .slide-enter-from, 610 | .slide-leave-to { 611 | margin-top: -300px; 612 | opacity: 0; 613 | } 614 | .timeline { 615 | margin-bottom: 30px; 616 | transition: margin-top 0.5s, opacity 0.3s, visibility 0.3s; 617 | } 618 | .timeline-content { 619 | background: #fff; 620 | border: 1px solid #0002; 621 | border-radius: 3px; 622 | margin-left: 17.5px; 623 | padding: 24px; 624 | transition: box-shadow 0.5s; 625 | } 626 | .timeline-content:hover { 627 | box-shadow: 0 2px 8px #00000017; 628 | } 629 | .timeline-tail { 630 | background: #fff; 631 | border: 2px solid #a5c2f5; 632 | border-radius: 50%; 633 | height: 7px; 634 | position: absolute; 635 | width: 7px; 636 | } 637 | ::-webkit-scrollbar { 638 | height: 12px; 639 | width: 12px; 640 | } 641 | ::-webkit-scrollbar-thumb { 642 | background: #8ab5ff 643 | linear-gradient( 644 | 45deg, 645 | #fff6 25%, 646 | transparent 25%, 647 | transparent 50%, 648 | #fff6 50%, 649 | #fff6 75%, 650 | transparent 75%, 651 | transparent 652 | ); 653 | border: 3px solid #e6efff; 654 | border-radius: 100px; 655 | } 656 | ::-webkit-scrollbar-track { 657 | background: #e6efff; 658 | border-radius: 100px; 659 | } 660 | ::selection { 661 | background-color: #3392ff2a; 662 | color: unset; 663 | } 664 | a { 665 | color: #66afef; 666 | text-decoration: none; 667 | } 668 | a:hover, 669 | .content .copycode:hover { 670 | opacity: 0.8; 671 | } 672 | audio, 673 | button, 674 | iframe, 675 | img, 676 | video, 677 | #home-head, 678 | #menu, 679 | .categories-tags a, 680 | .copycode, 681 | .friend-link a, 682 | .go-post, 683 | .hljs-ln-numbers, 684 | .icon-link a, 685 | .katex, 686 | .language, 687 | .page-current { 688 | user-select: none; 689 | } 690 | b, 691 | strong { 692 | font-weight: bold; 693 | line-height: 2.5; 694 | } 695 | blockquote { 696 | background: #d9e8ff6b; 697 | border-left: 3px solid #1e3e3f; 698 | border-radius: 3px; 699 | margin: 15px 0; 700 | overflow: auto; 701 | padding: 0 15px; 702 | } 703 | body { 704 | background: #f6f8fa; 705 | color: #1e3e3f; 706 | font: 500 14px Lexend, "Noto Sans SC", sans-serif; 707 | overflow-x: hidden; 708 | width: 100%; 709 | } 710 | code { 711 | background: #bddcf76b; 712 | border-radius: 4px; 713 | line-height: 2.5; 714 | padding: 4px 8px; 715 | } 716 | h1, 717 | h2, 718 | h3, 719 | h4, 720 | h5, 721 | h6 { 722 | color: #1e3e3f; 723 | font-weight: bold; 724 | margin: 15px 0; 725 | word-break: keep-all; 726 | } 727 | h1 { 728 | font-size: 30px; 729 | } 730 | h2 { 731 | font-size: 27px; 732 | } 733 | h3 { 734 | font-size: 24px; 735 | } 736 | h4 { 737 | font-size: 21px; 738 | } 739 | h5 { 740 | font-size: 18px; 741 | } 742 | h6 { 743 | font-size: 15px; 744 | } 745 | hr { 746 | border-style: dashed none none; 747 | border-width: 1.5px; 748 | } 749 | img, 750 | video, 751 | audio, 752 | iframe { 753 | border-radius: 10px; 754 | } 755 | mark { 756 | background: #fff13360; 757 | border-radius: 4px; 758 | color: unset; 759 | line-height: 2.5; 760 | padding: 4px 8px; 761 | } 762 | p, 763 | ul, 764 | ol { 765 | line-height: 1.7; 766 | margin: 15px 0; 767 | } 768 | pre { 769 | border: 1px solid #ebeef5; 770 | border-radius: 15px; 771 | box-shadow: 0 2px 12px 0 #0000001a; 772 | margin: 25px 0; 773 | overflow: hidden; 774 | white-space: normal; 775 | } 776 | pre, 777 | code, 778 | .hljs, 779 | .input, 780 | .language { 781 | font-family: "Fira Code", "Noto Sans SC", monospace; 782 | } 783 | table:not(.hljs-ln) { 784 | margin: 15px 0; 785 | } 786 | table:not(.hljs-ln) td:nth-child(even) { 787 | background: #c7e0fb4d; 788 | } 789 | table:not(.hljs-ln) td:nth-child(odd) { 790 | background: #d9e8ff4d; 791 | } 792 | table:not(.hljs-ln) th { 793 | background: #a3ddfb; 794 | } 795 | table:not(.hljs-ln) tr th, 796 | table:not(.hljs-ln) tr td { 797 | border-radius: 3px; 798 | padding: 10px 20px; 799 | } 800 | ul li, 801 | ol li { 802 | margin: 8px 0; 803 | } 804 | @keyframes loop1 { 805 | from { 806 | transform: rotate(30deg); 807 | } 808 | to { 809 | transform: rotate(390deg); 810 | } 811 | } 812 | @keyframes loop2 { 813 | from { 814 | transform: rotate(60deg); 815 | } 816 | to { 817 | transform: rotate(420deg); 818 | } 819 | } 820 | @keyframes loop3 { 821 | from { 822 | transform: rotate(90deg); 823 | } 824 | to { 825 | transform: rotate(450deg); 826 | } 827 | } 828 | @keyframes loop4 { 829 | from { 830 | transform: rotate(120deg); 831 | } 832 | to { 833 | transform: rotate(480deg); 834 | } 835 | } 836 | @media (min-width: 900px) { 837 | #home-head #home-info .info .wrap { 838 | padding: 25px; 839 | } 840 | #home-head #home-info .info .wrap h1 { 841 | font-size: 52px; 842 | font-weight: bold; 843 | margin-bottom: 10px; 844 | } 845 | #home-head #home-info .info .wrap h3 { 846 | font-size: 24px; 847 | margin: 10px 0; 848 | } 849 | #home-head #home-info .info .wrap h5 { 850 | font-size: 16px; 851 | margin: 20px 0; 852 | } 853 | #home-head #home-info .loop { 854 | display: inline-block; 855 | height: 500px; 856 | position: absolute; 857 | width: 500px; 858 | } 859 | #home-head #home-info, 860 | #home-head #home-info .info { 861 | height: 500px; 862 | width: 500px; 863 | } 864 | #home-posts { 865 | margin-right: 50px; 866 | width: 850px; 867 | } 868 | #home-posts .post { 869 | margin-bottom: 25px; 870 | padding: 50px; 871 | } 872 | #home-posts .post .description { 873 | padding: 20px 0; 874 | } 875 | #home-posts-wrap { 876 | max-width: 1200px; 877 | } 878 | #menu #desktop-menu { 879 | display: block; 880 | } 881 | #menu #mobile-menu { 882 | display: none; 883 | } 884 | .article, 885 | #archives, 886 | #footer #footer-wrap { 887 | width: 900px; 888 | } 889 | .home-posts-wrap-no-card #home-posts { 890 | margin: auto; 891 | } 892 | ul, 893 | ol { 894 | padding-left: 40px; 895 | } 896 | } 897 | @media (min-width: 900px) and (max-width: 1200px) { 898 | #home-card { 899 | display: none; 900 | } 901 | #home-posts { 902 | width: 100%; 903 | } 904 | #home-posts-wrap, 905 | #archives { 906 | width: 800px; 907 | } 908 | } 909 | @media (max-width: 900px) { 910 | #home-head #home-info { 911 | height: 350px; 912 | width: 350px; 913 | } 914 | #home-head #home-info .info { 915 | align-items: center; 916 | background: #ffffffa6; 917 | display: flex; 918 | height: 350px; 919 | justify-content: center; 920 | margin: auto; 921 | width: 350px; 922 | } 923 | #home-head #home-info .info .wrap { 924 | padding: 50px; 925 | } 926 | #home-head #home-info .info .wrap h1 { 927 | font-size: 46px; 928 | margin-bottom: 10px; 929 | } 930 | #home-head #home-info .info .wrap h3 { 931 | font-size: 20px; 932 | margin: 10px 0; 933 | } 934 | #home-head #home-info .info .wrap h5 { 935 | font-size: 14px; 936 | margin: 20px 0; 937 | } 938 | #home-head #home-info .loop { 939 | display: none; 940 | height: 350px; 941 | position: absolute; 942 | width: 350px; 943 | } 944 | #home-posts { 945 | margin: auto; 946 | width: 100%; 947 | } 948 | #home-posts .post { 949 | margin-bottom: 30px; 950 | padding: 20px 30px; 951 | } 952 | #home-posts .post .description { 953 | padding: 20px 0; 954 | } 955 | #home-posts .post .post-tags { 956 | padding-right: 69px; 957 | } 958 | #home-posts-wrap, 959 | .article, 960 | #archives, 961 | #footer #footer-wrap { 962 | width: 100%; 963 | } 964 | #menu #desktop-menu, 965 | #home-card { 966 | display: none; 967 | } 968 | #menu #mobile-menu { 969 | display: block; 970 | } 971 | ul, 972 | ol { 973 | padding-left: 20px; 974 | } 975 | } 976 | -------------------------------------------------------------------------------- /source/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argvchs/hexo-theme-particlex/d1bf2fdc23deedd014abc8bd2c1482282c865881/source/images/loading.gif -------------------------------------------------------------------------------- /source/js/lib/crypto.js: -------------------------------------------------------------------------------- 1 | mixins.crypto = { 2 | data() { 3 | return { crypto: "", cryptoStatus: "" }; 4 | }, 5 | watch: { 6 | crypto(value) { 7 | let input = this.$refs.crypto, 8 | content = this.$refs.content; 9 | let { encrypted, shasum } = input.dataset; 10 | try { 11 | let decrypted = CryptoJS.AES.decrypt(encrypted, value).toString(CryptoJS.enc.Utf8); 12 | if (CryptoJS.SHA256(decrypted).toString() === shasum) { 13 | this.cryptoStatus = "success"; 14 | content.innerHTML = decrypted; 15 | this.render(); 16 | } else this.cryptoStatus = "failure"; 17 | } catch { 18 | this.cryptoStatus = "failure"; 19 | } 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /source/js/lib/highlight.js: -------------------------------------------------------------------------------- 1 | mixins.highlight = { 2 | data() { 3 | return { copying: false }; 4 | }, 5 | created() { 6 | hljs.configure({ ignoreUnescapedHTML: true }); 7 | this.renderers.push(this.highlight); 8 | }, 9 | methods: { 10 | sleep(ms) { 11 | return new Promise((resolve) => setTimeout(resolve, ms)); 12 | }, 13 | highlight() { 14 | let codes = document.querySelectorAll("pre"); 15 | for (let i of codes) { 16 | let code = i.textContent; 17 | let language = [...i.classList, ...i.firstChild.classList][0] || "plaintext"; 18 | let highlighted; 19 | try { 20 | highlighted = hljs.highlight(code, { language }).value; 21 | } catch { 22 | highlighted = code; 23 | } 24 | i.innerHTML = ` 25 |
${highlighted}
26 |
${language}
27 |
28 | 29 | 30 |
31 | `; 32 | let content = i.querySelector(".code-content"); 33 | hljs.lineNumbersBlock(content, { singleLine: true }); 34 | let copycode = i.querySelector(".copycode"); 35 | copycode.addEventListener("click", async () => { 36 | if (this.copying) return; 37 | this.copying = true; 38 | copycode.classList.add("copied"); 39 | await navigator.clipboard.writeText(code); 40 | await this.sleep(1000); 41 | copycode.classList.remove("copied"); 42 | this.copying = false; 43 | }); 44 | } 45 | }, 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /source/js/lib/home.js: -------------------------------------------------------------------------------- 1 | mixins.home = { 2 | mounted() { 3 | let background = this.$refs.homeBackground; 4 | let images = background.dataset.images.split(","); 5 | let id = Math.floor(Math.random() * images.length); 6 | background.style.backgroundImage = `url('${images[id]}')`; 7 | this.menuColor = true; 8 | }, 9 | methods: { 10 | homeClick() { 11 | window.scrollTo({ top: window.innerHeight, behavior: "smooth" }); 12 | }, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /source/js/lib/math.js: -------------------------------------------------------------------------------- 1 | mixins.math = { 2 | created() { 3 | this.renderers.push(this.math); 4 | }, 5 | methods: { 6 | math() { 7 | renderMathInElement(document.body, { 8 | delimiters: [ 9 | { left: "$$", right: "$$", display: true }, 10 | { left: "$", right: "$", display: false }, 11 | { left: "\\(", right: "\\)", display: false }, 12 | { left: "\\[", right: "\\]", display: true }, 13 | ], 14 | }); 15 | }, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /source/js/lib/preview.js: -------------------------------------------------------------------------------- 1 | mixins.preview = { 2 | data() { 3 | return { previewShow: false }; 4 | }, 5 | created() { 6 | this.renderers.push(this.preview); 7 | }, 8 | methods: { 9 | preview() { 10 | let preview = this.$refs.preview, 11 | content = this.$refs.previewContent; 12 | let images = document.querySelectorAll("img"); 13 | for (let i of images) 14 | i.addEventListener("click", () => { 15 | content.alt = i.alt; 16 | content.src = i.src; 17 | this.previewShow = true; 18 | }); 19 | preview.addEventListener("click", () => { 20 | this.previewShow = false; 21 | }); 22 | window.addEventListener("resize", () => { 23 | this.previewShow = false; 24 | }); 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /source/js/lib/search.js: -------------------------------------------------------------------------------- 1 | mixins.search = { 2 | data() { 3 | return { rawSearch: "" }; 4 | }, 5 | watch: { 6 | search(value) { 7 | let timeline = this.$refs.timeline.childNodes; 8 | for (let i of timeline) 9 | if (!value || i.dataset.title.includes(value)) { 10 | i.style.opacity = 1; 11 | i.style.visibility = "visible"; 12 | i.style.marginTop = 0; 13 | } else { 14 | i.style.opacity = 0; 15 | i.style.visibility = "hidden"; 16 | i.style.marginTop = -i.offsetHeight - 30 + "px"; 17 | } 18 | }, 19 | }, 20 | computed: { 21 | search() { 22 | return this.rawSearch.toLowerCase().replace(/\s+/g, ""); 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /source/js/main.js: -------------------------------------------------------------------------------- 1 | const app = Vue.createApp({ 2 | mixins: Object.values(mixins), 3 | data() { 4 | return { 5 | loading: true, 6 | hiddenMenu: false, 7 | showMenuItems: false, 8 | menuColor: false, 9 | scrollTop: 0, 10 | renderers: [], 11 | }; 12 | }, 13 | created() { 14 | window.addEventListener("load", () => { 15 | this.loading = false; 16 | }); 17 | }, 18 | mounted() { 19 | window.addEventListener("scroll", this.handleScroll, true); 20 | this.render(); 21 | }, 22 | methods: { 23 | render() { 24 | for (let i of this.renderers) i(); 25 | }, 26 | handleScroll() { 27 | let wrap = this.$refs.homePostsWrap; 28 | let newScrollTop = document.documentElement.scrollTop; 29 | if (this.scrollTop < newScrollTop) { 30 | this.hiddenMenu = true; 31 | this.showMenuItems = false; 32 | } else this.hiddenMenu = false; 33 | if (wrap) { 34 | if (newScrollTop <= window.innerHeight - 100) this.menuColor = true; 35 | else this.menuColor = false; 36 | if (newScrollTop <= 400) wrap.style.top = "-" + newScrollTop / 5 + "px"; 37 | else wrap.style.top = "-80px"; 38 | } 39 | this.scrollTop = newScrollTop; 40 | }, 41 | }, 42 | }); 43 | app.mount("#layout"); 44 | --------------------------------------------------------------------------------