├── .gitignore ├── LICENSE ├── README.draft.md ├── README.en.md ├── README.ja.md ├── README.md ├── _config.yml ├── demo.jpg ├── friend_Links.md ├── languages ├── en-us.yml └── zh-cn.yml ├── layout ├── archive.pug ├── category.pug ├── includes │ ├── archive-aside.pug │ ├── aside.pug │ ├── bottom-btn.pug │ ├── generate-css.pug │ ├── header.pug │ ├── js-data.pug │ ├── layout.pug │ ├── meta-data.pug │ ├── pjax.pug │ └── recent-posts.pug ├── index.pug ├── page.pug ├── post.pug └── tag.pug ├── package.json ├── scripts ├── filters │ ├── checkbox.js │ ├── lightgallery.js │ ├── minify.js │ └── pandoc.js ├── generator │ ├── encrypt.js │ └── search │ │ ├── database.js │ │ └── generator.js └── tags │ ├── admonition.js │ ├── hide.js │ └── link-card.js ├── source ├── 404.html ├── audio │ └── bgm.mp3 ├── css │ ├── _core │ │ ├── aside │ │ │ ├── aside.styl │ │ │ ├── icp.styl │ │ │ ├── layout │ │ │ │ ├── left.styl │ │ │ │ └── right.styl │ │ │ └── toc.styl │ │ ├── base.styl │ │ ├── color │ │ │ ├── atom-one.styl │ │ │ ├── base.styl │ │ │ ├── change.styl │ │ │ ├── dark.styl │ │ │ └── light.styl │ │ ├── core.styl │ │ ├── cursor.styl │ │ ├── header │ │ │ ├── flex_layout.styl │ │ │ ├── header.styl │ │ │ ├── layout │ │ │ │ ├── left.styl │ │ │ │ └── right.styl │ │ │ ├── navBtn.styl │ │ │ └── navSecond.styl │ │ ├── layout │ │ │ ├── flex_layout.styl │ │ │ └── single_page.styl │ │ └── scrollbar.styl │ ├── _custom │ │ └── custom.styl │ ├── _modules │ │ ├── canvas_dust.styl │ │ ├── cards │ │ │ ├── admonition.styl │ │ │ ├── hide.styl │ │ │ └── link-card.styl │ │ ├── comments │ │ │ ├── comments.styl │ │ │ ├── gitalk.styl │ │ │ ├── selector.styl │ │ │ ├── valine.styl │ │ │ └── waline.styl │ │ ├── expand.styl │ │ ├── lightgallery.styl │ │ ├── modules.styl │ │ ├── pjax.styl │ │ ├── search │ │ │ ├── base.styl │ │ │ ├── left.styl │ │ │ ├── right.styl │ │ │ └── single_page.styl │ │ └── social.styl │ ├── _page │ │ ├── archive.styl │ │ ├── article.styl │ │ ├── category.styl │ │ ├── page.styl │ │ ├── post │ │ │ ├── MathJax.styl │ │ │ ├── bottom_btn.styl │ │ │ ├── code.styl │ │ │ └── post.styl │ │ └── tag.styl │ └── arknights.styl ├── favicon.ico ├── font │ ├── Bender.ttf │ ├── BenderLight.woff2 │ ├── Geometos.woff2 │ └── JetBrainsMono-Regular.woff2 ├── icons │ └── sound.svg ├── img │ ├── bg.jpg │ ├── bk.jpg │ ├── faction │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ └── 5.png │ └── pc-bg.jpg ├── js │ ├── _src │ │ ├── include │ │ │ ├── BgmControl.ts │ │ │ ├── Code.ts │ │ │ ├── ColorMode.ts │ │ │ ├── Comments.ts │ │ │ ├── Cursors.ts │ │ │ ├── Expands.ts │ │ │ ├── Header.ts │ │ │ ├── Index.ts │ │ │ ├── Scroll.ts │ │ │ ├── canvaDust.ts │ │ │ ├── common │ │ │ │ ├── base.ts │ │ │ │ ├── enviroment.d.ts │ │ │ │ └── selectors.ts │ │ │ └── pjaxSupport.ts │ │ └── tsconfig.json │ ├── arknights.js │ ├── gitalk.js │ ├── pjax.js │ └── search.js └── lib │ ├── encrypt │ ├── hbe.js │ └── hbe.style.css │ └── fontawesome │ ├── css │ └── all.min.css │ └── webfonts │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff2 │ ├── fa-v4compatibility.ttf │ └── fa-v4compatibility.woff2 └── support.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /package-lock.json 3 | .idea 4 | .vscode 5 | .vs 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yue_plus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.draft.md: -------------------------------------------------------------------------------- 1 | # Theme arknights 2 | 3 | 一个《明日方舟》罗德岛阵营的 Hexo 主题。 4 | 5 | A Hexo Theme for *RHODES ISLAND* in *Arknights*. 6 | 7 | 项目地址: 8 | 9 | License 10 | GitHub Release 11 | GitHub Commits 12 | 13 | GitHub Watchers GitHub Stars GitHub Forks 14 | 15 | ![ScreenShot](./demo.jpg) 16 | 17 |

zh-CN 简体中文 | zh-HK 繁體中文 | en-US English | ja-JP 日本語

18 | 19 | 文档: 20 | 主题配置 | 21 | 文章配置 22 | 23 | ## 预览 24 | 25 | - **Dr.Yue_plus: ** 26 | - [其他使用者的友链](./friend_Links.md) 27 | 28 | ## 快速使用 29 | 30 | Hexo Version 31 | Node Version 32 | 33 | ### 建议参考本项目 Wiki [快速使用](https://github.com/Yue-plus/hexo-theme-arknights/wiki/%E5%BF%AB%E9%80%9F%E4%BD%BF%E7%94%A8) 34 | 35 | ### 1. 搭建 Hexo 博客 36 | 37 | 如果你还没有 Hexo 博客,请按照[Hexo 官方文档](https://hexo.io/zh-cn/docs/)进行安装、建站。 38 | 39 | ### 2. 获取主题最新版本 40 | 41 | 下载最新 release 版本解压到 `themes` 目录,并将解压出的文件夹重命名为 `arknights`。 42 | 43 | 然后在博客目录下创建 `_config.arknights.yml` 即主题的配置文件,将主题的 `_config.yml` 内容复制进去。 44 | 45 | ### 3. 指定主题 46 | 47 | 对 Hexo 博客目录中的 `_config.yml` 进行如下修改: 48 | 49 | ``` yaml 50 | theme: arknights # 指定主题 51 | 52 | highlight: # 开启代码高亮 53 | hljs: true 54 | ``` 55 | 56 | ### 4. 安装依赖 57 | 58 | npm 用户: 59 | ``` shell script 60 | npm install hexo-server hexo-browsersync hexo-renderer-pug --save 61 | ``` 62 | 63 | yarn 用户: 64 | ``` shell script 65 | yarn add hexo-server hexo-browsersync hexo-renderer-pug 66 | ``` 67 | 68 | ## 高级使用方法 69 | 70 | 参考本项目 Wiki [高级使用方法](https://github.com/Yue-plus/hexo-theme-arknights/wiki/%E9%AB%98%E7%BA%A7%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95)。 71 | 72 | ## 更新主题 73 | 74 | 参考本项目 Wiki [更新主题](https://github.com/Yue-plus/hexo-theme-arknights/wiki/%E6%9B%B4%E6%96%B0%E4%B8%BB%E9%A2%98)。 75 | 76 | ## 功能特性 77 | 78 | - [x] 无比详实的[用户文档](https://github.com/Yue-plus/hexo-theme-arknights/wiki) 79 | - [x] 内置多款评论插件 80 | - [x] 支持 LaTeX 数学公式 81 | - [x] 支持 mermaid 流程图 82 | 83 | ## 贡献 84 | 85 | 所有的贡献者请查看[光荣榜](https://github.com/Yue-plus/hexo-theme-arknights/wiki/%E5%85%89%E8%8D%A3%E6%A6%9C)页面,衷心感谢他们对 arknights 主题的付出。 86 | 87 | 欢迎您对 arknights 主题做出贡献。若您有希望加入的功能,可以给我们提出 Issue ,或者自己动手实现,然后发起 Pull Request。 88 | 89 | 有关于如何做出贡献的更详细内容,请查看[如何做出贡献](https://github.com/Yue-plus/hexo-theme-arknights/wiki/%E5%A6%82%E4%BD%95%E5%81%9A%E5%87%BA%E8%B4%A1%E7%8C%AE)。 90 | 91 | ## 支持我们 92 | 93 | 喜欢这个主题的话可以: 94 | 95 | - 给颗小星星吧 `(/▽\)` 96 | > - [x] `ヾ(✿゚▽゚)ノ` 100star 做个新主题哦~ 97 | > - [ ] 新主题开发中 [Yue-plus/vuepress-theme-rhinelab](https://github.com/Yue-plus/vuepress-theme-rhinelab) 98 | - 开发者的B服ID:`24444750` 99 | - 加入 QQ 群:618221514 100 | > 群内开发为主,吹水晒卡,分享线索7也都欢迎哦~ `d=====( ̄▽ ̄*)b` 101 | - 打赏、赞助: 102 | 103 | ![收款二维码](./support.jpg) -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # 标签页图标 2 | favicon: 3 | type: "image/x-icon" 4 | href: "/favicon.ico" 5 | 6 | # canvas 动态背景 7 | canvas_dust: true 8 | 9 | # 默认颜色模式 dark / dark-only / light / light-only / auto 10 | # dark 暗色模式 11 | # light 亮色模式 12 | # -only 锁定颜色模式 13 | # auto 跟随系统 14 | color: dark 15 | 16 | # 背景图片链接 17 | background_image: 18 | dark: https://ak.hypergryph.com/assets/index/images/ak/pc/bk.jpg # 暗色模式 19 | light: /img/bk.jpg # 亮色模式 20 | 21 | # 导航栏 22 | menu: 23 | Home: "" 24 | # About: about/ 25 | # Contact: contact/ 26 | Archives: archives/ 27 | 28 | # 侧边栏 29 | aside: 30 | in_left: false # 侧边栏在左 true / false 31 | logo: https://ak.hypergryph.com/assets/index/images/ak/pc/faction/1.png #图片链接,建议 1:1 比例 32 | logo_margin: 0 # 为 Logo 图片设置 CSS margin 属性值,参考:https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin 33 | logo_border_radius: 0 # 为 Logo 图片设置 CSS border-radius 属性值,参考:https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-radius 34 | dr: / # 侧边栏 Dr. 链接 35 | icp: # ICP 备案号,与版权声明相同,但会链接到 https://beian.miit.gov.cn/ 36 | copyright: # 版权声明、备案号等,可自定义键值,不想显示则留空 37 | # 萌: 38 | # 萌ICP备XXXXXXXX号: https://icp.gov.moe/?keyword=XXXXXXXX 39 | # copyright: 40 | # CC BY-NC-SA 4.0: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh 41 | 42 | # 社交链接 43 | # 格式:链接 || 图标 44 | # 图标支持链接与 FontAwesome 45 | # FontAwesome 格式可用图标参考:https://fontawesome.com/icons 46 | social: 47 | # GitHub: https://github.com/yourname || fab fa-github 48 | # E-Mail: mailto:yourname@gmail.com || fa fa-envelope 49 | # BiliBili: https://space.bilibili.com/0000000 || fa-brands fa-bilibili 50 | # Weibo: https://weibo.com/yourname || fab fa-weibo 51 | # Zhihu: https://www.zhihu.com/people/yourname || fab fa-zhihu 52 | 53 | # post 文章页面配置;true / false 54 | post: 55 | date: true # 是否显示发布日期 56 | updated: true # 是否显示修改日期 57 | excerpt: true # 是否在文章中显示摘要内容( 以上的内容) 58 | # 文章末显示打赏二维码 59 | reward: 60 | # 支付宝 | Alipay: img/Alipay.png 61 | # 微信 | Wechat: img/WeChat.png 62 | # 以下两项依赖 hexo-wordcount,请参阅 README 开启 63 | count: false # 是否显示字数统计 64 | time: false # 是否显示预计阅读时长 65 | code_fold: 15 # 当代码小于等此行数时默认展开,设为 -1 则全部展开 66 | 67 | # 文章内目录 68 | toc: 69 | list_number: true # true / false ;是否显示编号 70 | max_depth: 6 # 最大目录深度 71 | min_depth: 1 # 最小目录深度 72 | 73 | # 归档页 74 | archives: 75 | categories_count: true # 是否显示分类总数 76 | tags_count: true # 是否显示标签总数 77 | 78 | # 搜索 79 | search: 80 | enable: true 81 | content: true # 若为 false,仅可搜索标题及 metadata 82 | preload: false # 自动加载搜索数据 83 | # 设为 post 时,仅可搜索 post 页面 84 | # 设为 page 时,仅可搜索非 post 页面 85 | # 设为 all 时,可搜索全部页面 86 | field: post 87 | # 设为 html 时,依据 html 文件生成 88 | # 设为 striptags 时,滤除 html tag 89 | # 设为 raw 时,依据 markdown 源文件生成 90 | format: striptags 91 | 92 | # 背景音乐 93 | bgm: 94 | enable: true 95 | autoplay: true 96 | loop: true 97 | src: /audio/bgm.mp3 98 | 99 | # 不蒜子 100 | # 详见 http://busuanzi.ibruce.info/ 101 | busuanzi: 102 | enable: false 103 | sitePV: true # 站点总访问量 104 | siteUV: true # 站点访客数 105 | pagePV: true # 页面访问量 106 | 107 | # Valine 108 | # 详见 https://valine.js.org 109 | valine: 110 | enable: false 111 | app_id: # APP ID 112 | app_key: # APP KEY 113 | server_url: # APP DOMAIN(LeanCloud 国际版) 114 | avatar: 'retro' # (''/mp/identicon/monsterid/wavatar/robohash/retro/hide) 115 | avatar_cdn: 'https://dn-qiniu-avatar.qbox.me/avatar/' # 自定义 avatar cdn 116 | 117 | # gitalk 118 | # 详见 https://github.com/gitalk/gitalk 119 | gitalk: 120 | enable: false 121 | client_id: # GitHub 应用 Client ID 122 | client_secret: # GitHub 应用 Client Secret 123 | repo: # 用于存放评论数据的 GitHub 仓库 124 | owner: # 该 GitHub 仓库所有者 125 | admin: [] # 具有写该 GitHub 仓库权限的用户,例如: [adminA,adminB] 126 | id: location.pathname # (可选) 页面的唯一标识 127 | 128 | # Waline 129 | # 详情: https://waline.js.org/ 130 | waline: 131 | enable: false 132 | server_url: #Server_Url 133 | 134 | #Artalk 135 | #详见:https://artalk.js.org/ 136 | artalk: 137 | enable: false 138 | server: https://artalk.server.instance/ # 你的 Artalk 服务地址 139 | site_name: My Blog # 站点名称,用于区分多个站点(可选) 140 | 141 | # 图表支持 142 | mermaid: 143 | enable: true 144 | version: "10.5.0" 145 | 146 | # pjax 支持 147 | pjax: 148 | enable: true 149 | 150 | # 公式前端渲染 151 | mathjax: 152 | enable: false 153 | version: "2.6.1" 154 | 155 | # 在 `` 标签内引入 CSS 样式表 156 | # 支持直接引入短片段,用 "{ }" 包裹(包括引号),例: - "{a {color: #2bf}}" 157 | stylesheets: 158 | 159 | # 在 `` 尾部引入 JavaScript 脚本 160 | # 支持直接引入短片段,用 "{ }" 包裹(包括引号),例: - "{var test='test'}" 161 | scripts: 162 | -------------------------------------------------------------------------------- /demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/demo.jpg -------------------------------------------------------------------------------- /friend_Links.md: -------------------------------------------------------------------------------- 1 | # 友情链接 2 | 3 | 这里记录了所有本主题使用者的友链: 4 | 5 | - ### **Dr.Yue_plus: ** 6 | - ### **Dr.ToUNVRSe ** 7 | - **Dr.Ye: ** 8 | - **Dr.tyqtyq ** 9 | - **Dr.Angine ** 10 | - **Dr.sjfhsjfh ** 11 | - **Dr.Voilone ** 12 | - **Dr.yuanli-LFSW** 13 | - **Dr.Laplacian: ** 14 | - **Dr.Chen: ** 15 | - **Dr.Linyee ** 16 | - **Dr.Flacier ** 17 | - **Dr.LZW ** 18 | - **Dr.GrandpaFox ** 19 | - **Dr.未雨屏 ** 20 | - **飞龙project ** 21 | - **tomorinao-www ** 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 如果使用了这个主题,欢迎发起 [Pull Requests](https://github.com/Yue-plus/hexo-theme-arknights/compare) 在这儿贴友链~ 30 | -------------------------------------------------------------------------------- /languages/en-us.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: english 3 | 4 | page: 5 | readMore: READ MORE + 6 | noTag: empty 7 | noCategory: NO CATEGORY 8 | sticky: TOP 9 | 10 | busuanzi: 11 | loading: "loading..." 12 | siteView: "Site View: " 13 | siteVisitor: "Visitor: " 14 | pageView: "Page View: " 15 | 16 | post: 17 | posted: "First Post: " 18 | edited: "Last Update: " 19 | countTotal: "Word Count: " 20 | timeTotal: "Read Time: " 21 | timeUnit: min 22 | index: Catalog 23 | reward: reward 24 | noTitle: No Title 25 | next: ← Next 26 | prev: Prev → 27 | 28 | encrypt: 29 | confirm: confirm 30 | 31 | code: 32 | codeInfo: $0 - $1 lines 33 | copy: copy 34 | 35 | btn: 36 | index: To Catalog 37 | totop: To Top 38 | colorMode: Change Theme 39 | 40 | menu: 41 | archive: 42 | name: Archive 43 | plural: Archives 44 | navigation: NAVIGATION 45 | tag: 46 | name: Tag 47 | plural: Tags 48 | category: 49 | name: Category 50 | plural: Categories 51 | empty: None. 52 | total: Total 53 | 54 | search: 55 | activeHolder: Enter here 56 | blurHolder: Search 57 | noResult: Data "$0" not found 58 | 59 | footer: 60 | publish: Published with 61 | theme: Theme 62 | by: by 63 | 64 | valine: 65 | placeHolder: This comment is sent by Penguin Logistics. 66 | -------------------------------------------------------------------------------- /languages/zh-cn.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 简体中文 3 | 4 | page: 5 | readMore: 阅读文章 + 6 | noTag: 无标签 7 | noCategory: 无分类 8 | sticky: 置顶 9 | 10 | busuanzi: 11 | loading: "加载中..." 12 | siteView: "总访问量:" 13 | siteVisitor: "访客数:" 14 | pageView: "页面浏览: " 15 | 16 | post: 17 | posted: "文章发布时间: " 18 | edited: "最后更新时间: " 19 | countTotal: "文章总字数: " 20 | timeTotal: "预计阅读时间: " 21 | timeUnit: 分钟 22 | index: 目录 23 | reward: 打赏 24 | noTitle: 无标题 25 | next: ← 下一篇 26 | prev: 上一篇 → 27 | 28 | encrypt: 29 | confirm: 确认 30 | 31 | code: 32 | codeInfo: $0 - $1 行 33 | copy: 复制 34 | 35 | btn: 36 | totop: 回到顶部 37 | index: 文章目录 38 | colorMode: 切换主题 39 | 40 | menu: 41 | archive: 42 | name: 文章 43 | plural: 文章 44 | navigation: 导航 45 | tag: 46 | name: 标签 47 | plural: 标签 48 | category: 49 | name: 分类 50 | plural: 分类 51 | empty: 无 52 | total: 总数 53 | 54 | search: 55 | activeHolder: 键入以继续 56 | blurHolder: 数据检索 57 | noResult: 无 $0 相关数据 58 | 59 | footer: 60 | publish: 构建自 61 | theme: 使用主题 62 | by: 主题作者 63 | 64 | valine: 65 | placeHolder: 此条评论委托企鹅物流发送 66 | -------------------------------------------------------------------------------- /layout/archive.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | - 5 | const categoriesList = list_categories({ 6 | order: 1 7 | , show_count: theme.archives.categories_count 8 | }) 9 | - 10 | const tagsList = list_tags({ 11 | order: -1 12 | , show_count: theme.archives.tags_count 13 | }) 14 | - 15 | const archivesList = list_archives({ 16 | type: 'yearly' 17 | , order: -1 18 | , show_count: false 19 | }) 20 | 21 | #archive-flex 22 | include includes/archive-aside.pug 23 | #Archives 24 | h1 #{__('menu.archive.plural')} 25 | #Archives-bg 26 | - let year 27 | - page.posts.each((article) => { 28 | - let yearMonth = date(article.date, 'YYYY-MM') 29 | if yearMonth !== year 30 | - year = yearMonth 31 | h2= year 32 | .article-item 33 | .control-archive 34 | time= date(article.date, 'MM-DD') 35 | a(href=url_for(article.path) target="_blank") 36 | = article.title || __('post.noTitle') 37 | - }) 38 | if config.per_page != 0 39 | #paginator!= paginator() 40 | 41 | block aside-block 42 | h1 #{__('menu.navigation')} 43 | #navigation 44 | a(href='#Archives') #{__('menu.archive.plural')} 45 | a(href='#Categories') #{__('menu.category.plural')} 46 | a(href='#Tags') #{__('menu.tag.plural')} 47 | -------------------------------------------------------------------------------- /layout/category.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | - 5 | const categoriesList = list_categories({ 6 | order: 1 7 | , show_count: theme.archives.categories_count 8 | }) 9 | - 10 | const tagsList = list_tags({ 11 | order: -1 12 | , show_count: theme.archives.tags_count 13 | }) 14 | - 15 | const archivesList = list_archives({ 16 | type: 'yearly' 17 | , order: -1 18 | , show_count: false 19 | }) 20 | 21 | #archive-flex 22 | include includes/archive-aside.pug 23 | #Archives 24 | h1 #{__('menu.category.name')}: #{page.category} 25 | #Archives-bg 26 | - let year 27 | - page.posts.each((article) => { 28 | - let yearMonth = date(article.date, 'YYYY-MM') 29 | if yearMonth !== year 30 | - year = yearMonth 31 | h2= year 32 | .article-item 33 | .control-archive 34 | time= date(article.date, 'MM-DD') 35 | a(href=url_for(article.path) target="_blank") 36 | = article.title || __('post.noTitle') 37 | - }) 38 | if config.per_page != 0 39 | #paginator!= paginator() 40 | -------------------------------------------------------------------------------- /layout/includes/archive-aside.pug: -------------------------------------------------------------------------------- 1 | #archive-aside 2 | #Categories 3 | h1 #{__('menu.category.plural')} 4 | if categoriesList 5 | != categoriesList 6 | else 7 | p #{__('menu.empty')} 8 | #Tags 9 | h1 #{__('menu.tag.plural')} 10 | if tagsList 11 | != tagsList 12 | else 13 | p #{__('menu.empty')} 14 | -------------------------------------------------------------------------------- /layout/includes/aside.pug: -------------------------------------------------------------------------------- 1 | aside 2 | #about 3 | a(href=config.root)#logo 4 | img(src= asideLogo, alt= "Logo", style= { 5 | margin: theme.aside.logo_margin, 6 | 'border-radius': theme.aside.logo_border_radius 7 | }) 8 | h1#Dr 9 | a(href= theme.aside.dr)= config.author 10 | #description 11 | p!= config.description 12 | if theme.social 13 | #social-links 14 | each value, name in theme.social 15 | - let icon = value.split('||')[1].trim(), src = value.split('||')[0].trim() 16 | if icon.substring(0,2) === 'fa' 17 | a.social(href= src) 18 | i(alt= name,class= icon) 19 | else 20 | a.social.img(href= src) 21 | img(alt= name,src= icon) 22 | #aside-block 23 | block aside-block 24 | if page.title === undefined 25 | section#total 26 | a#total-archives(href= url_for("archives")) 27 | span.total-title #{__('menu.archive.plural')} #{__('menu.total')}: 28 | span.total-number= site.posts.length 29 | #total-tags 30 | span.total-title #{__('menu.tag.plural')}: 31 | span.total-number= site.tags.length 32 | #total-categories 33 | span.total-title #{__('menu.category.plural')}: 34 | span.total-number= site.categories.length 35 | if theme.busuanzi.enable 36 | br 37 | #total-view 38 | if theme.busuanzi.sitePV 39 | span#busuanzi_container_site_pv(class='total-title') #{__('busuanzi.siteView')} 40 | span#busuanzi_value_site_pv(class='total-number') #{__('busuanzi.loading')} 41 | br 42 | if theme.busuanzi.siteUV 43 | span#busuanzi_container_site_uv(class='total-title') #{__('busuanzi.siteVisitor')} 44 | span#busuanzi_value_site_uv(class='total-number') #{__('busuanzi.loading')} 45 | footer(style= footerStyle) 46 | if theme.aside.icp !== null 47 | nobr 48 | span.icp-title ICP 49 | a(href='https://beian.miit.gov.cn/').icp-content= theme.aside.icp 50 | br 51 | if theme.aside.copyright !== null 52 | each content, title in theme.aside.copyright 53 | nobr 54 | span.icp-title= title 55 | if typeof content === 'string' 56 | span.icp-content= content 57 | else 58 | each href, name in content 59 | a(href=href).icp-content= name 60 | br 61 | nobr #{__('footer.publish')} 62 | a(href= 'http://hexo.io') Hexo 63 | wbr 64 | nobr #{__('footer.theme')} 65 | a(href= 'https://github.com/Yue-plus/hexo-theme-arknights') Arknights 66 | wbr 67 | nobr #{__('footer.by')} 68 | a(href= 'https://github.com/Yue-plus') Yue_plus 69 | -------------------------------------------------------------------------------- /layout/includes/bottom-btn.pug: -------------------------------------------------------------------------------- 1 | .bottom-btn 2 | div 3 | a#to-top.i-top(onClick="scrolls.scrolltop();" title=__('btn.totop') style="opacity: 0; display: none;") ∧ 4 | if page.content 5 | - const encrypted = page.encrypt || page.password 6 | - const tocContent = encrypted === undefined ? toc(page.content, theme.toc) : toc(page.origin, theme.toc) 7 | if tocContent.length > 0 8 | a#to-index.i-index(href="#toc-div" title=__('btn.index')) ≡ 9 | if theme.color !== 'dark-only' && theme.color !== 'light-only' 10 | a#color-mode.i-color(onClick="colorMode.change()" title=__('btn.colorMode')) 11 | if theme.bgm.enable 12 | a(onclick="BgmControl()") 13 | svg(id="bgm-control" viewBox="0 0 30 34" fill=theme.bgm.autoplay ? "#18d1ff" : "currentColor" style="width: 24px; transition: transform .3s;margin-top: 4px") 14 | path(d="M25.998 23.422V11.29h3.999v12.132h-3.999zM19.497 6.234h4.001v22.243h-4.001V6.234zM12.998.867h4v32.978h-4V.867zm-6.5 5.367h4.001v22.243H6.498V6.234zm-6.5 5.056h4v12.132h-4V11.29z") 15 | audio(id='bgm' src=theme.bgm.src autoplay=theme.bgm.autoplay loop=theme.bgm.loop crossorigin='anonymous') 16 | -------------------------------------------------------------------------------- /layout/includes/generate-css.pug: -------------------------------------------------------------------------------- 1 | style. 2 | :root { 3 | --dark-background: url('#{url_for(theme.background_image.dark)}'); 4 | --light-background: url('#{url_for(theme.background_image.light)}'); 5 | --theme-encrypt-confirm: '#{__("encrypt.confirm")}' 6 | } 7 | -------------------------------------------------------------------------------- /layout/includes/header.pug: -------------------------------------------------------------------------------- 1 | mixin expand_list(list) 2 | each url, label in list 3 | - var match = null 4 | if typeof(url) === "string" && url.match(config.archive_dir) 5 | - match = config.category_dir + ',' + config.tag_dir 6 | li.navItem(matchdata=match) 7 | if typeof(url) === "object" 8 | .navSecond 9 | span.navItemTitle= label 10 | ol.navItemList 11 | +expand_list(url) 12 | else 13 | a.navSecond(href= url_for(url)) 14 | span.navItemTitle= label 15 | 16 | header.closed 17 | .navBtn 18 | i.navBtnIcon 19 | span.navBtnIconBar 20 | span.navBtnIconBar 21 | span.navBtnIconBar 22 | nav 23 | if searchConfig !== null 24 | .navItem#search-header 25 | span.navItemTitle 26 | input(autocomplete="off" autocorrect="off" autocapitalize="none" 27 | placeholder=__('search.blurHolder') spellcheck="false" maxlength="50" 28 | type="text" id="search-input") 29 | .navItem#search-holder 30 | .search-popup(tabindex="0") 31 | #search-result 32 | ol.navContent 33 | each url, label in theme.menu 34 | - var match = null 35 | if typeof(url) === "string" && url.match(config.archive_dir) 36 | - match = config.category_dir + ',' + config.tag_dir 37 | li.navItem(matchdata=match) 38 | if typeof(url) === "object" 39 | .navBlock 40 | span.navItemTitle= label 41 | ol.navItemList 42 | +expand_list(url) 43 | else 44 | a.navBlock(href= url_for(url)) 45 | span.navItemTitle= label 46 | -------------------------------------------------------------------------------- /layout/includes/js-data.pug: -------------------------------------------------------------------------------- 1 | script(defer src=url_for("js/arknights.js")) 2 | 3 | if searchConfig !== null 4 | script(defer src=url_for("js/search.js")) 5 | 6 | if theme.busuanzi && theme.busuanzi.enable === true 7 | script(async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js") 8 | 9 | if theme.valine && theme.valine.enable === true 10 | script(async src='//unpkg.com/valine/dist/Valine.min.js') 11 | 12 | if theme.gitalk && theme.gitalk.enable === true 13 | script(async src=url_for("js/gitalk.js")) 14 | 15 | if theme.mermaid && theme.mermaid.enable === true && theme.mermaid.version 16 | script(defer type='module'). 17 | import mermaid from '#{"//unpkg.com/mermaid@" + theme.mermaid.version + "/dist/mermaid.esm.mjs"}'; 18 | window.mermaid = mermaid; 19 | code.paintMermaid(); 20 | 21 | if theme.waline && theme.waline.enable === true 22 | script(async type='module'). 23 | import { init } from '//unpkg.com/@waline/client@v2/dist/waline.mjs'; 24 | window.waline = init; 25 | 26 | if theme.mathjax && theme.mathjax.enable === true 27 | script(src="//cdnjs.cloudflare.com/ajax/libs/mathjax/" + theme.mathjax.version + "/MathJax.js") 28 | script. 29 | MathJax.Hub.Config({ 30 | menuSettings: { 31 | zoom: "None" 32 | }, 33 | showMathMenu: false, 34 | jax: ["input/TeX","output/CommonHTML"], 35 | extensions: ["tex2jax.js"], 36 | TeX: { 37 | extensions: ["AMSmath.js","AMSsymbols.js"], 38 | equationNumbers: { 39 | autoNumber: "AMS" 40 | } 41 | }, 42 | tex2jax: { 43 | inlineMath: [["\\(", "\\)"]], 44 | displayMath: [["\\[", "\\]"]] 45 | } 46 | }); 47 | 48 | script(async src="//unpkg.com/lightgallery@2.7.1/lightgallery.min.js") 49 | script(async src="//unpkg.com/lightgallery@2.7.1/plugins/zoom/lg-zoom.min.js") 50 | script(async src="//unpkg.com/lightgallery@2.7.1/plugins/thumbnail/lg-thumbnail.min.js") 51 | script(async src=url_for("/lib/encrypt/hbe.js")) 52 | include ./pjax.pug 53 | script.pjax-js reset= () => { 54 | if theme.valine && theme.valine.enable === true 55 | |new Valine({ 56 | | el: '#valine' 57 | | , appId: '#{theme.valine.app_id}' 58 | | , appKey: '#{theme.valine.app_key}' 59 | if theme.valine.server_url 60 | | , serverURLs: '#{theme.valine.server_url}' 61 | | , placeholder: '#{__('valine.placeHolder')}' 62 | | , path: !{'window.location.pathname'} 63 | | , avatar: '#{theme.valine.avatar}' 64 | | , avatar_cdn: '#{theme.valine.avatar_cdn}' 65 | |}); 66 | if theme.artalk && theme.artalk.enable === true 67 | |Artalk.init({ 68 | | el: '#artalk', 69 | | server: '#{theme.artalk.server}', 70 | if theme.color === "dark" || theme.color === "dark-only" 71 | | darkMode: 'true', 72 | else if theme.color === "auto" 73 | | darkMode: 'auto', 74 | if theme.artalk.site_name 75 | | site: '#{theme.artalk.site_name}', 76 | |}); 77 | if theme.gitalk && theme.gitalk.enable === true 78 | - let config = theme.gitalk, gitAdmin = '' 79 | for str in theme.gitalk.admin 80 | - gitAdmin= gitAdmin + "'" + str + "'" 81 | |gitalk = new Gitalk({ 82 | | clientID: '#{config.client_id}', 83 | | clientSecret: '#{config.client_secret}', 84 | | repo: '#{config.repo}', 85 | | owner: '#{config.owner}', 86 | | admin: [#{gitAdmin}], 87 | | distractionFreeMode: #{config.distraction_free_mode || false}, 88 | | id: #{config.id ? config.id : ""} 89 | |}); 90 | |if (document.querySelector("#gitalk")) gitalk.render("gitalk"); 91 | if theme.waline && theme.waline.enable === true 92 | |if (document.querySelector('#waline')) 93 | | waline({ 94 | | el: '#waline', 95 | | dark: ':root[theme-mode="dark"]', 96 | | serverURL: '#{theme.waline.server_url}', 97 | | path: !{'window.location.pathname'}, 98 | | }); 99 | if theme.mathjax && theme.mathjax.enable === true 100 | |MathJax.Hub.Queue(["Typeset", MathJax.Hub]); 101 | | document.querySelector('.lg-container')?.remove() 102 | | lightGallery(document.getElementById('post-bg'), { 103 | | plugins: [lgZoom,lgThumbnail], 104 | | selector: '.item-img'})} 105 | 106 | script window.addEventListener("load",() => { 107 | if pjax 108 | |pjax = new Pjax({ 109 | | cacheBust: false, 110 | | selectors: ['title','article','#aside-block','.pjax-js'], 111 | | switches: {'article': Pjax.switches.sideBySide}, 112 | | switchesOptions: { 113 | | 'article': { 114 | | classNames: { 115 | | remove: "pjax-out", 116 | | add: "pjax-in" 117 | | } 118 | | } 119 | | } 120 | |}); 121 | |document.addEventListener("pjax:complete", reset); 122 | | reset()}) 123 | -------------------------------------------------------------------------------- /layout/includes/layout.pug: -------------------------------------------------------------------------------- 1 | - 2 | let pageTitle = page.title || config.subtitle || '' 3 | if (is_post()) pageTitle = page.title 4 | if (is_archive()) pageTitle = __('menu.archive.plural') 5 | if (is_tag()) pageTitle = __('menu.tag.plural') + ': ' + page.tag 6 | if (is_category()) pageTitle = __('menu.category.plural') + ': ' + page.category 7 | if (is_month()) pageTitle += ': ' + page.month + '/' + page.year 8 | if (is_year()) pageTitle += ': ' + page.year 9 | if (pageTitle) pageTitle += ' | ' 10 | pageTitle += config.title 11 | const asideLogo = theme.aside.logo 12 | const pjax = theme.pjax ? theme.pjax.enable : false 13 | let searchConfig = null 14 | if (theme.search !== undefined && theme.search.enable === true) searchConfig = theme.search; 15 | const configs = JSON.stringify({ 16 | root: config.root, 17 | code_fold: config.theme_config.post.code_fold, 18 | search: { 19 | preload: searchConfig.preload, 20 | activeHolder: __('search.activeHolder'), 21 | blurHolder: __('search.blurHolder'), 22 | noResult: __('search.noResult') 23 | }, 24 | code: { 25 | codeInfo: __('code.codeInfo'), 26 | copy: __('code.copy') 27 | } 28 | }) 29 | 30 | doctype html 31 | html(lang=config.language theme-mode=theme.color) 32 | head 33 | include ./meta-data.pug 34 | body 35 | if pjax 36 | .loading(style="opacity: 0;") 37 | .loadingBar.left 38 | .loadingBar.right 39 | main 40 | include ./header.pug 41 | article 42 | if body 43 | div!= body 44 | else 45 | block content 46 | include ./bottom-btn.pug 47 | include ./aside.pug 48 | if theme.canvas_dust 49 | canvas#canvas-dust 50 | 51 | if theme.scripts && theme.scripts.length > 0 52 | //- scripts list from config.yml 53 | each url in theme.scripts 54 | if url 55 | if url[0] === '{' && url[url.length - 1] === '}' 56 | script!=url 57 | else 58 | script(defer src=url) 59 | -------------------------------------------------------------------------------- /layout/includes/meta-data.pug: -------------------------------------------------------------------------------- 1 | meta(charset='UTF-8') 2 | meta(name='viewport' content='width=device-width, initial-scale=1.0') 3 | title= pageTitle 4 | 5 | link( 6 | rel="icon" 7 | type=(theme.favicon.type ? theme.favicon.type : "image/x-icon") 8 | href=(url_for(theme.favicon.href ? theme.favicon.href : "favicon.ico")) 9 | ) 10 | 11 | link(rel="preload", as="font", crossorigin="anonymous", href=url_for("font/Bender.ttf")) 12 | link(rel="preload", as="font", crossorigin="anonymous", href=url_for("font/BenderLight.woff2")) 13 | link(rel="preload", as="font", crossorigin="anonymous", href=url_for('font/JetBrainsMono-Regular.woff2')) 14 | link(rel="stylesheet", href=url_for("css/arknights.css")) 15 | style. 16 | @font-face { 17 | font-family: Bender; 18 | src: local('Bender'), url("#{config.root}font/Bender.ttf"), url("#{config.root}font/Bender.otf"); 19 | } 20 | @font-face { 21 | font-family: BenderLight; 22 | src: local('BenderLight'), url("#{config.root}font/BenderLight.ttf"); 23 | } 24 | @font-face { 25 | font-family: 'JetBrains Mono'; 26 | src: local('JetBrains Mono'), url('#{config.root}font/JetBrainsMono-Regular.woff2') format('woff2'); 27 | } 28 | 29 | script. 30 | var config = !{configs}; 31 | var page_config = { 32 | title: !{JSON.stringify(page.title)}, 33 | path: !{JSON.stringify(page.path)}, 34 | date: !{JSON.stringify(page.date)}, 35 | updated: !{JSON.stringify(page.updated)}, 36 | code_fold: !{JSON.stringify(page.code_fold || null)} 37 | }; 38 | if theme.waline && theme.waline.enable === true 39 | link(rel="stylesheet", href= url_for('//unpkg.com/@waline/client@v2/dist/waline.css')) 40 | link(type="text/css" rel="stylesheet" href=url_for("/lib/encrypt/hbe.style.css")) 41 | if theme.gitalk && theme.gitalk.enable === true 42 | script(src=url_for("js/gitalk.js")) 43 | if theme.artalk && theme.artalk.enable === true 44 | link(type="text/css" rel="stylesheet" href="//unpkg.com/artalk@2.8.4/dist/Artalk.css") 45 | script(async src="//unpkg.com/artalk@2.8.4/dist/Artalk.js") 46 | if theme.mermaid && theme.mermaid.enable === true && theme.mermaid.version 47 | script(src= "//unpkg.com/mermaid@" + theme.mermaid.version + "/dist/mermaid.min.js") 48 | if theme.mathjax && theme.mathjax.enable === true 49 | script(src="//cdnjs.cloudflare.com/ajax/libs/mathjax/" + theme.mathjax.version + "/MathJax.js") 50 | script 51 | |MathJax.Hub.Config({ 52 | | menuSettings: { 53 | | zoom: "None" 54 | | }, 55 | | showMathMenu: false, 56 | | jax: ["input/TeX","output/CommonHTML"], 57 | | extensions: ["tex2jax.js"], 58 | | TeX: { 59 | | extensions: ["AMSmath.js","AMSsymbols.js"], 60 | | equationNumbers: { 61 | | autoNumber: "AMS" 62 | | } 63 | | }, 64 | | tex2jax: { 65 | | inlineMath: [["\\(", "\\)"]], 66 | | displayMath: [["\\[", "\\]"]] 67 | | } 68 | |}); 69 | link(type="text/css" rel="stylesheet" href="//unpkg.com/lightgallery@2.7.1/css/lightgallery.css") 70 | link(type="text/css" rel="stylesheet" href="//unpkg.com/lightgallery@2.7.1/css/lg-zoom.css") 71 | link(type="text/css" rel="stylesheet" href="//unpkg.com/lightgallery@2.7.1/css/lg-thumbnail.css") 72 | link(type="text/css" rel="stylesheet" href=url_for("/lib/fontawesome/css/all.min.css")) 73 | 74 | 75 | if theme.stylesheets && theme.stylesheets.length > 0 76 | //- stylesheets list from _config.yml 77 | each url in theme.stylesheets 78 | if url 79 | if url[0] === '{' && url[url.length - 1] === '}' 80 | style!=url.substr(1, url.length - 2) 81 | else 82 | style(defer src=url) 83 | link(rel='stylesheet', href=url) 84 | script 85 | |if (window.localStorage.getItem('theme-mode') === 'light' 86 | if theme.color === 'auto' 87 | | || window.matchMedia('(prefers-color-scheme:light)').matches 88 | |) 89 | | document.documentElement.setAttribute('theme-mode', 'light') 90 | |if (window.localStorage.getItem('theme-mode') === 'dark' 91 | if theme.color === 'auto' 92 | | || window.matchMedia('(prefers-color-scheme:dark)').matches 93 | |) 94 | | document.documentElement.setAttribute('theme-mode', 'dark') 95 | style 96 | |@font-face { 97 | | font-family: BenderLight; 98 | | src: local('Bender'), url("#{config.root}font/BenderLight.woff2") format('woff2'); 99 | |} 100 | |@font-face { 101 | | font-family: 'JetBrains Mono'; 102 | | src: local('JetBrains Mono'), url('#{config.root}font/JetBrainsMono-Regular.woff2') format('woff2'); 103 | |} 104 | 105 | include ./generate-css.pug 106 | include ./js-data.pug 107 | -------------------------------------------------------------------------------- /layout/includes/pjax.pug: -------------------------------------------------------------------------------- 1 | if pjax 2 | script(async src=url_for("js/pjax.js")) 3 | 4 | script.pjax-js reset= () => { 5 | if theme.valine && theme.valine.enable === true 6 | |new Valine({ 7 | | el: '#valine' 8 | | , appId: '#{theme.valine.app_id}' 9 | | , appKey: '#{theme.valine.app_key}' 10 | if theme.valine.server_url 11 | | , serverURLs: '#{theme.valine.server_url}' 12 | | , placeholder: '#{__('valine.placeHolder')}' 13 | | , path: !{'window.location.pathname'} 14 | | , avatar: '#{theme.valine.avatar}' 15 | | , avatar_cdn: '#{theme.valine.avatar_cdn}' 16 | |}); 17 | if theme.gitalk && theme.gitalk.enable === true 18 | - let config = theme.gitalk, gitAdmin = '' 19 | for str in theme.gitalk.admin 20 | - gitAdmin= gitAdmin + "'" + str + "'" 21 | |gitalk = new Gitalk({ 22 | | clientID: '#{config.client_id}', 23 | | clientSecret: '#{config.client_secret}', 24 | | repo: '#{config.repo}', 25 | | owner: '#{config.owner}', 26 | | admin: [#{gitAdmin}], 27 | | distractionFreeMode: #{config.distraction_free_mode || false}, 28 | | id: #{config.id ? config.id : ""} 29 | |}); 30 | |if (document.querySelector("#gitalk")) gitalk.render("gitalk"); 31 | if theme.waline && theme.waline.enable === true 32 | |if (document.querySelector('#waline')) 33 | | waline({ 34 | | el: '#waline', 35 | | dark: ':root[theme-mode="dark"]', 36 | | serverURL: '#{theme.waline.server_url}', 37 | | path: !{'window.location.pathname'}, 38 | | }); 39 | | document.querySelector('.lg-container')?.remove() 40 | | lightGallery(document.getElementById('post-bg'), { 41 | | plugins: [lgZoom,lgThumbnail], 42 | | selector: '.item-img'})} 43 | 44 | script window.addEventListener("load",() => { 45 | if pjax 46 | |pjax = new Pjax({ 47 | | cacheBust: false, 48 | | selectors: ['title','article','#aside-block','.pjax-js','data-pjax','.busuanzi'], 49 | | switches: {'article': Pjax.switches.sideBySide}, 50 | | switchesOptions: { 51 | | 'article': { 52 | | classNames: { 53 | | remove: "pjax-out", 54 | | add: "pjax-in" 55 | | } 56 | | } 57 | | } 58 | |}); 59 | |document.addEventListener("pjax:complete", reset); 60 | if theme.busuanzi.enable 61 | |document.addEventListener('pjax:success', _ => bszCaller.fetch( 62 | | "//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback", a => { 63 | | bszTag.texts(a), 64 | | bszTag.shows() 65 | |})); 66 | | reset()}) 67 | -------------------------------------------------------------------------------- /layout/includes/recent-posts.pug: -------------------------------------------------------------------------------- 1 | if page.posts.length > 0 2 | each post in page.posts.limit((config.per_page === 0) ? 9999999 : config.per_page).toArray() 3 | a(href=url_for(post.path)).recent-post 4 | object 5 | .recent-info 6 | span.categories 7 | if post.categories.length > 0 8 | each category in post.categories.data 9 | object 10 | a(href=url_for(category.path))= category.name 11 | else 12 | span #{__('page.noCategory')} 13 | span.tags 14 | if post.tags.length > 0 15 | each tag in post.tags.data 16 | object 17 | a(href=url_for(tag.path))= tag.name 18 | else 19 | span #{__('page.noTag')} 20 | if post.date 21 | time(datetime=post.date.toJSON())= date(post.date, date_format) 22 | h1.recent-title 23 | if post.sticky > 0 24 | span.post-sticky #{__('page.sticky')} 25 | = post.title 26 | .recent-excerpt 27 | if post.excerpt.length > 0 28 | hr 29 | != post.excerpt 30 | span.read-more #{__('page.readMore')} 31 | -------------------------------------------------------------------------------- /layout/index.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | .posts 5 | include includes/recent-posts.pug 6 | #paginator!= paginator() 7 | -------------------------------------------------------------------------------- /layout/page.pug: -------------------------------------------------------------------------------- 1 | extends ./post.pug 2 | -------------------------------------------------------------------------------- /layout/post.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | - 5 | const prev = page.prev 6 | const next = page.next 7 | const dateConf = page['post-time'] !== false && theme.post.date 8 | const updatedConf = page['post-time' ] !== false && theme.post.updated 9 | const excerptConf = theme.post.excerpt 10 | const reward = theme.post.reward 11 | const encrypted = page.encrypt || page.password 12 | const content = encrypted === undefined ? page.content : page.origin 13 | const tocContent = toc(content, theme.toc) 14 | const countWord = page['post-count'] !== false && theme.post.count === true && wordcount !== undefined ? wordcount(content) : null 15 | const countTime = page['post-count'] !== false && theme.post.time === true && min2read !== undefined ? min2read(content) : null 16 | const busuanzi = page.busuanzi !== false && theme.busuanzi.enable 17 | #post-bg 18 | #post-title 19 | h1= page.title 20 | if (dateConf || updatedConf || countWord || countTime || busuanzi) && page.title && page['post-info'] !== false 21 | #post-info 22 | - var first = true 23 | if dateConf 24 | span #{__('post.posted')} 25 | div.control 26 | time(datetime=page.date.toJSON())#date 27 | = ' ' + date(page.date, date_format) 28 | - first = false 29 | if updatedConf 30 | if !first 31 | br 32 | span #{__('post.edited')} 33 | div.control 34 | time(datetime=page.updated.toJSON())#updated 35 | = ' ' + date(page.updated, date_format) 36 | - first = false 37 | if countWord 38 | if !first 39 | br 40 | span #{__('post.countTotal')} 41 | div.control #{countWord} 42 | - first = false 43 | if countTime 44 | if !first 45 | br 46 | span #{__('post.timeTotal')} 47 | div.control #{countTime} #{__('post.timeUnit')} 48 | - first = false 49 | if busuanzi 50 | if !first 51 | br 52 | span#busuanzi_container_page_pv #{__('busuanzi.pageView')} 53 | span#busuanzi_value_page_pv(class='control') #{__('busuanzi.loading')} 54 | - first = false 55 | hr 56 | #post-content 57 | if excerptConf || encrypted 58 | != page.content 59 | else 60 | != page.more 61 | #paginator!= paginator() 62 | #post-footer 63 | if prev || next 64 | - let fix = "" 65 | if prev === undefined 66 | - fix = "justify-content: flex-end" 67 | if next === undefined 68 | - fix = "justify-content: flex-start" 69 | #pages(style=fix) 70 | if prev !== undefined 71 | .footer-link(style="width: 50%;text-align:right;border-right:1px #fe2 solid") 72 | a(href=url_for(prev.path)) 73 | |#{__('post.next')} 74 | = ' ' + prev.title 75 | if next !== undefined 76 | .footer-link(style="width: 50%;right:1px;border-left:1px #fe2 solid") 77 | a(href=url_for(next.path)) 78 | = next.title + ' ' 79 | |#{__('post.prev')} 80 | if reward 81 | details#reward 82 | summary #{__('post.reward')} 83 | each imgSrc, pay in reward 84 | div 85 | span #{pay} 86 | br 87 | img(src=url_for(imgSrc)) 88 | - 89 | let count = (theme.valine.enable === true) + 90 | (theme.gitalk.enable === true) + 91 | (theme.waline.enable === true) + 92 | (theme.artalk.enable === true) 93 | if page.comments && count 94 | #comments 95 | if count > 1 96 | .selector 97 | if theme.valine.enable === true 98 | button.valine-sel 99 | if theme.gitalk.enable === true 100 | button.gitalk-sel 101 | if theme.waline.enable === true 102 | button.waline-sel 103 | if theme.artalk.enable === true 104 | button.artalk-sel 105 | if theme.valine.enable === true 106 | #valine 107 | if theme.gitalk.enable === true 108 | #gitalk 109 | if theme.waline.enable === true 110 | #waline 111 | if theme.artalk.enable === true 112 | #artalk 113 | 114 | block aside-block 115 | - 116 | const encrypted = page.encrypt || page.password 117 | const tocContent = encrypted === undefined ? toc(page.content, theme.toc) : toc(page.origin, theme.toc) 118 | if (tocContent.length > 0) 119 | #toc-div(style=encrypted !== undefined?"display:none":"") 120 | h1 #{__('post.index')} 121 | |!{tocContent} 122 | -------------------------------------------------------------------------------- /layout/tag.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | - 5 | const categoriesList = list_categories({ 6 | order: 1 7 | , show_count: theme.archives.categories_count 8 | }) 9 | - 10 | const tagsList = list_tags({ 11 | order: -1 12 | , show_count: theme.archives.tags_count 13 | }) 14 | - 15 | const archivesList = list_archives({ 16 | type: 'yearly' 17 | , order: -1 18 | , show_count: false 19 | }) 20 | 21 | #archive-flex 22 | include includes/archive-aside.pug 23 | #Archives 24 | h1 #{__('menu.tag.name')}: #{page.tag} 25 | #Archives-bg 26 | - let year 27 | - page.posts.each((article) => { 28 | - let yearMonth = date(article.date, 'YYYY-MM') 29 | if yearMonth !== year 30 | - year = yearMonth 31 | h2= year 32 | .article-item 33 | .control-archive 34 | time= date(article.date, 'MM-DD') 35 | a(href=url_for(article.path) target="_blank") 36 | = article.title || __('post.noTitle') 37 | - }) 38 | if config.per_page != 0 39 | #paginator!= paginator() 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-theme-arknights", 3 | "version": "1.15.0", 4 | "description": "一款明日方舟罗德岛阵营的 Hexo 主题", 5 | "author": "yue-plus (https://github.com/Yue-plus)", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/Yue-plus/hexo-theme-arknights.git" 9 | }, 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/Yue-plus/hexo-theme-arknights/issues" 13 | }, 14 | "homepage": "https://github.com/Yue-plus/hexo-theme-arknights#readme", 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1", 17 | "build": "tsc -p source/js/_src/tsconfig.json" 18 | }, 19 | "keywords": [], 20 | "dependencies": { 21 | "hexo-browsersync": "^0.3.0", 22 | "hexo-renderer-pug": "^2.0.0", 23 | "hexo-renderer-stylus": "^2.1.0", 24 | "hexo-server": "^2.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/filters/checkbox.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function fixCheckBox(str) { 6 | return str.replaceAll(/)/g, (match) => { 7 | return '
  • { 12 | data.content = fixCheckBox(data.content) 13 | data.more = fixCheckBox(data.more) 14 | return data 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/filters/lightgallery.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function findImg(content) { 6 | return content.replaceAll(/<[^>]*?>\s*?/g, (match) => { 7 | const tag = match.match(/<[^>]*?(?=>\s*/)[0], 9 | src = img.match(/((?<=src="|').*?(?="|'))|((?<=src=)[^'" ]*?(?= |>))/)[0] 10 | return `${tag} class='item-img' data-src='${src}'>${img}` 11 | }) 12 | } 13 | 14 | hexo.extend.filter.register('after_post_render', (data) => { 15 | data.content = findImg(data.content) 16 | data.more = findImg(data.more) 17 | return data 18 | }); 19 | -------------------------------------------------------------------------------- /scripts/filters/minify.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | hexo.extend.filter.register('after_generate', () => { 6 | const theme = hexo.theme.config; 7 | 8 | if (theme.search !== undefined && !theme.search.enable && hexo.config.search !== undefined && !hexo.config.search.enable) { 9 | hexo.route.remove('js/search.js'); 10 | } 11 | 12 | if (theme.gitalk !== undefined && !theme.gitalk.enable) { 13 | hexo.route.remove('js/gitalk.js'); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /scripts/filters/pandoc.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function initHeader(str) { 6 | return str.replaceAll(/.*?<\/h[1-6]>/g, (match) => { 7 | let link = match.match(/(?<=id=").*?(?=")/)[0], 8 | pre = match.match(//)[0], 9 | nxt = match.slice(pre.length) 10 | if (!match.match(/<\/a>/g)) { 11 | return `${pre}${nxt}` 12 | } 13 | return match 14 | }) 15 | } 16 | 17 | hexo.extend.filter.register('after_post_render', (data) => { 18 | data.content = initHeader(data.content) 19 | data.more = initHeader(data.more) 20 | return data 21 | }); 22 | -------------------------------------------------------------------------------- /scripts/generator/encrypt.js: -------------------------------------------------------------------------------- 1 | /* global hexo, __dirname */ 2 | 3 | 'use strict'; 4 | 5 | const crypto = require('crypto'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const log = hexo.log; 9 | 10 | const defaultConfig = { 11 | 'abstract': 'Here\'s something encrypted, password is required to continue reading.', 12 | 'message': 'Hey, password is required here.', 13 | 'theme': 'default', 14 | 'wrong_pass_message': 'Oh, this is an invalid password. Check and try again, please.', 15 | 'wrong_hash_message': 'OOPS, these decrypted content may changed, but you can still have a look.', 16 | 'silent': false, 17 | }; 18 | 19 | const keySalt = crypto.randomBytes(32); 20 | const ivSalt = crypto.randomBytes(32); 21 | 22 | // As we can't detect the wrong password with AES-CBC, 23 | // so adding an empty tag and check it when decrption. 24 | const knownPrefix = ""; 25 | 26 | // disable log 27 | var silent = false; 28 | // use default theme 29 | var theme = 'default'; 30 | 31 | hexo.extend.filter.register('after_post_render', (data) => { 32 | const tagEncryptPairs = []; 33 | 34 | let password = data.password; 35 | let tagUsed = false; 36 | 37 | // use a empty password to disable category encryption 38 | if (password === "") { 39 | return data; 40 | } 41 | 42 | if (hexo.config.encrypt === undefined) { 43 | hexo.config.encrypt = []; 44 | } 45 | 46 | if(('encrypt' in hexo.config) && ('tags' in hexo.config.encrypt)){ 47 | hexo.config.encrypt.tags.forEach((tagObj) => { 48 | tagEncryptPairs[tagObj.name] = tagObj.password; 49 | }); 50 | } 51 | 52 | if (data.tags) { 53 | data.tags.forEach((cTag) => { 54 | if (tagEncryptPairs.hasOwnProperty(cTag.name)) { 55 | tagUsed = password ? tagUsed : cTag.name; 56 | password = password || tagEncryptPairs[cTag.name]; 57 | } 58 | }); 59 | } 60 | 61 | if(password == undefined){ 62 | return data; 63 | } 64 | 65 | password = password.toString(); 66 | 67 | // make sure toc can work. 68 | data.origin = data.content; 69 | 70 | // Let's rock n roll 71 | const config = Object.assign(defaultConfig, hexo.config.encrypt, data); 72 | silent = config.silent; 73 | theme = config.theme.trim().toLowerCase(); 74 | 75 | // deprecate the template keyword 76 | if (config.template) { 77 | dlog('warn', 'Looks like you use a deprecated property "template" to set up template, consider to use "theme"? See https://github.com/D0n9X1n/hexo-blog-encrypt#encrypt-theme'); 78 | } 79 | 80 | // read theme from file 81 | let template = `
    82 | 85 |
    86 |
    87 | 88 | 91 |
    92 | 93 |
    94 |
    95 | ` 96 | 97 | if (tagUsed === false) { 98 | dlog('info', `hexo-blog-encrypt: encrypting "${data.title.trim()}" based on the password configured in Front-matter with theme: ${theme}.`); 99 | } else { 100 | dlog('info', `hexo-blog-encrypt: encrypting "${data.title.trim()}" based on Tag: "${tagUsed}" with theme ${theme}.`); 101 | } 102 | 103 | data.content = knownPrefix + data.content.trim(); 104 | data.encrypt = true; 105 | 106 | const key = crypto.pbkdf2Sync(password, keySalt, 1024, 32, 'sha256'); 107 | const iv = crypto.pbkdf2Sync(password, ivSalt, 512, 16, 'sha256'); 108 | 109 | const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); 110 | const hmac = crypto.createHmac('sha256', key); 111 | 112 | let encryptedData = cipher.update(data.content, 'utf8', 'hex'); 113 | hmac.update(data.content, 'utf8'); 114 | encryptedData += cipher.final('hex'); 115 | const hmacDigest = hmac.digest('hex'); 116 | 117 | data.content = template.replace(/{{hbeEncryptedData}}/g, encryptedData) 118 | .replace(/{{hbeHmacDigest}}/g, hmacDigest) 119 | .replace(/{{hbeWrongPassMessage}}/g, config.wrong_pass_message) 120 | .replace(/{{hbeWrongHashMessage}}/g, config.wrong_hash_message) 121 | .replace(/{{hbeMessage}}/g, config.message) 122 | .replace(/{{hbeKeySalt}}/g, keySalt.toString('hex')) 123 | .replace(/{{hbeIvSalt}}/g, ivSalt.toString('hex')); 124 | data.excerpt = data.more = config.abstract; 125 | return data; 126 | }, 1000); 127 | 128 | // log function 129 | function dlog(level, x) { 130 | switch (level) { 131 | case 'warn': 132 | log.warn(x); 133 | break; 134 | 135 | case 'info': 136 | default: 137 | if (silent) { 138 | return; 139 | } 140 | 141 | log.info(x); 142 | } 143 | } 144 | 145 | // Utils functions 146 | function textToArray(s) { 147 | var i = s.length; 148 | var n = 0; 149 | var ba = new Array() 150 | 151 | for (var j = 0; j < i;) { 152 | var c = s.codePointAt(j); 153 | if (c < 128) { 154 | ba[n++] = c; 155 | j++; 156 | } else if ((c > 127) && (c < 2048)) { 157 | ba[n++] = (c >> 6) | 192; 158 | ba[n++] = (c & 63) | 128; 159 | j++; 160 | } else if ((c > 2047) && (c < 65536)) { 161 | ba[n++] = (c >> 12) | 224; 162 | ba[n++] = ((c >> 6) & 63) | 128; 163 | ba[n++] = (c & 63) | 128; 164 | j++; 165 | } else { 166 | ba[n++] = (c >> 18) | 240; 167 | ba[n++] = ((c >> 12) & 63) | 128; 168 | ba[n++] = ((c >> 6) & 63) | 128; 169 | ba[n++] = (c & 63) | 128; 170 | j += 2; 171 | } 172 | } 173 | 174 | return new Uint8Array(ba); 175 | } 176 | -------------------------------------------------------------------------------- /scripts/generator/search/database.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { stripHTML } = require('hexo-util'); 4 | 5 | function savedb(article, config, isPost) { 6 | const data = {}; 7 | if (article.title) { 8 | data.title = article.title; 9 | } 10 | if (article.path) { 11 | data.url = encodeURI(config.root + article.path); 12 | } 13 | if (config.content !== false) { 14 | if (config.format === 'raw') { 15 | data.content = article._content; 16 | } else { 17 | data.content = article.content.replace(/.*?<\/td>/g, ''); 18 | if (config.format === 'striptags') { 19 | data.content = stripHTML(data.content); 20 | } 21 | } 22 | } else { 23 | data.content = ''; 24 | } 25 | if (!isPost) { 26 | return data; 27 | } 28 | if (article.categories && article.categories.length > 0) { 29 | data.categories = article.categories.map(category => category.name); 30 | } 31 | if (article.tags && article.tags.length > 0) { 32 | data.tags = article.tags.map(tag => tag.name); 33 | } 34 | return data; 35 | } 36 | 37 | module.exports = function (locals, config) { 38 | const searchfield = config.field; 39 | const database = []; 40 | if (searchfield === 'all' || searchfield === 'post') { 41 | locals.posts.each(post => { 42 | const data = savedb(post, config, true); 43 | database.push(data); 44 | }); 45 | } 46 | if (searchfield === 'all' || searchfield === 'page') { 47 | locals.pages.each(page => { 48 | const data = savedb(page, config); 49 | database.push(data); 50 | }); 51 | } 52 | return database; 53 | }; 54 | -------------------------------------------------------------------------------- /scripts/generator/search/generator.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | hexo.extend.generator.register('json', function (locals) { 4 | if (!hexo.theme.config.search.enable) { 5 | return {} 6 | } 7 | const config = Object.assign({ 8 | root: hexo.config.root, 9 | path: 'search.json', 10 | field: 'post', 11 | content: true, 12 | format: 'striptags' 13 | }, hexo.theme.config.search); 14 | const database = require('./database')(locals, config); 15 | return { 16 | path: config.path, 17 | data: JSON.stringify(database) 18 | }; 19 | }); 20 | -------------------------------------------------------------------------------- /scripts/tags/admonition.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function isStatus(str) { 6 | return str === 'open' || str === 'fold'; 7 | } 8 | 9 | function genBlock(name, args, data) { 10 | let title = args.length > 0 ? args[0] : name[0].toUpperCase() + name.slice(1); 11 | let color = '', status = 'fold'; 12 | for (let i = 1; i < args.length; ++i) { 13 | if (!isStatus(args[i])) { 14 | color = args[i]; 15 | } else { 16 | status = args[i]; 17 | } 18 | } 19 | return `
    21 |
    22 | 23 | ${name !== 'detail' ? `` : ''} 24 | ${ 25 | hexo.render.renderSync({ text: title, engine: 'markdown' }).replaceAll(/

    |<\/p>/g,"") 26 | } 27 |

    28 |
    ${hexo.render.renderSync({ text: data, engine: 'markdown' })}
    29 |
    `; 30 | } 31 | 32 | hexo.extend.tag.register('success', (args, data) => { 33 | return genBlock('success', args, data); 34 | }, { ends: true }) 35 | 36 | hexo.extend.tag.register('warning', (args, data) => { 37 | return genBlock('warning', args, data); 38 | }, { ends: true }) 39 | 40 | hexo.extend.tag.register('note', (args, data) => { 41 | return genBlock('note', args, data); 42 | }, { ends: true }) 43 | 44 | hexo.extend.tag.register('failure', (args, data) => { 45 | return genBlock('failure', args, data); 46 | }, { ends: true }) 47 | 48 | hexo.extend.tag.register('detail', (args, data) => { 49 | return genBlock('detail', args, data); 50 | }, { ends: true }) 51 | -------------------------------------------------------------------------------- /scripts/tags/hide.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function render(data) { 6 | return hexo.render.renderSync({ text: data, engine: 'markdown' }); 7 | } 8 | 9 | hexo.extend.tag.register('hide', (args) => { 10 | let content = '' 11 | args.forEach((item) => { 12 | content += ' ' + item 13 | }); 14 | return `${render(content.slice(1)).trim()}`; 15 | }) 16 | -------------------------------------------------------------------------------- /scripts/tags/link-card.js: -------------------------------------------------------------------------------- 1 | /* global hexo */ 2 | 3 | 'use strict'; 4 | 5 | function getStyle(arg) { 6 | if (!arg) { 7 | return ''; 8 | } 9 | let result = 'style="'; 10 | for (let key in arg[0]) { 11 | result += key + ':' + arg[0][key] + ';'; 12 | } 13 | return result + '" '; 14 | } 15 | 16 | function render(data) { 17 | return hexo.render.renderSync({ text: data, engine: 'yaml' }); 18 | } 19 | 20 | function quote(str) { 21 | if (!str) return "''"; 22 | if (str[0] !== '"' || str[0] !== "'") { 23 | return "'" + str + "'"; 24 | } 25 | return str; 26 | } 27 | 28 | function linkCard(_args, data) { 29 | let result = '', res = render(data); 30 | for (let i in res) { 31 | let item = res[i], 32 | name = ``, 33 | href = item.src, 34 | avatar = item.avatar ? `` : '', 35 | descr = item.descr ? `` : '', 36 | img = item.img ? `` : '', 37 | content = ``; 38 | if (!href.match('//')) { 39 | href = '//' + href; 40 | } 41 | result += ` 46 | ${img} 47 | `; 48 | } 49 | return result; 50 | } 51 | 52 | hexo.extend.tag.register('linkcard', (_args, data) => { 53 | return linkCard(_args, data); 54 | }, { ends: true }) 55 | 56 | hexo.extend.tag.register('linkc', (_args, data) => { 57 | return linkCard(_args, data); 58 | }, { ends: true }) 59 | -------------------------------------------------------------------------------- /source/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | エラー発生。 8 | 80 | 81 | 82 | 83 |
    84 | 87 |
    88 |

    エラー発生。

    89 |

    404 NOT FOUND

    90 |

    91 | 首页 92 | 上一页 93 |

    94 |
    95 |
    96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /source/audio/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/audio/bgm.mp3 -------------------------------------------------------------------------------- /source/css/_core/aside/aside.styl: -------------------------------------------------------------------------------- 1 | aside 2 | &::-webkit-scrollbar 3 | display none 4 | &::-ms-scrollbar 5 | display none 6 | scrollbar-width none 7 | height 100vh 8 | position sticky 9 | display flex 10 | flex-direction column 11 | justify-content space-between 12 | align-content stretch 13 | overflow-y auto 14 | overflow-x hidden 15 | color var(--theme-text-light) 16 | padding 0 20px 17 | h1 18 | transition .6s 19 | font-family BenderLight, sans-serif 20 | margin-top 0 21 | footer 22 | color var(--theme-unimportant) 23 | padding 0 3px 30px 3px 24 | font-family Bender 25 | font-weight bold 26 | 27 | #logo 28 | user-select none 29 | width 100% 30 | height 5px 31 | display inline-block 32 | margin-bottom 100% 33 | padding 0 34 | img 35 | width 100% 36 | 37 | #Dr 38 | text-align center 39 | margin-bottom 0 40 | a 41 | color var(--theme-text-light) 42 | 43 | #total 44 | font-family BenderLight 45 | div 46 | display inline-block 47 | 48 | #navigation, #total 49 | background-color var(--theme-bg-trans1) 50 | 51 | #total-archives 52 | color var(--theme-text-light) 53 | box-sizing border-box 54 | width 100% 55 | border-left 5px solid var(--theme-border-light) 56 | padding 0 0 0 10px 57 | display inline-block 58 | transition .3s 59 | .total-title 60 | font-size 23px 61 | display block 62 | .total-number 63 | font-weight bolder 64 | padding 0 10px 65 | transition .3s 66 | @media ( min-width 769px ) 67 | &:hover 68 | border-color var(--theme-highlight) 69 | background-color var(--theme-bg-soft-hover) 70 | .total-number 71 | color var(--theme-highlight) 72 | 73 | #total-tags, #total-categories, #total-view 74 | margin 5px 5px 5px 10px 75 | 76 | #aside-block 77 | flex-grow 2 78 | margin-top 1em 79 | h1 80 | color var(--theme-text-rev) 81 | background-color var(--theme-text-light) 82 | margin 0 83 | padding 0 10px 84 | font-size medium 85 | #total-archives .total-number 86 | letter-spacing 2px 87 | #toc-div 88 | background linear-gradient(var(--theme-bg-trans1), var(--theme-bg-trans1) calc(100% - 15px), transparent) 89 | @media ( min-width 769px ) 90 | &:hover h1 91 | background-color var(--theme-highlight) 92 | 93 | #description p 94 | margin unset 95 | text-align center 96 | -------------------------------------------------------------------------------- /source/css/_core/aside/icp.styl: -------------------------------------------------------------------------------- 1 | .icp-title, .icp-content 2 | display inline-block 3 | padding 0 5px 4 | height 18px 5 | color black 6 | font-size small 7 | font-weight normal 8 | font-family sans-serif 9 | line-height 18px 10 | .icp-title 11 | background-color var(--theme-highlight) 12 | .icp-content 13 | margin 0 10px 0 0 14 | padding 0 28px 0 5px 15 | background-color white 16 | -------------------------------------------------------------------------------- /source/css/_core/aside/layout/left.styl: -------------------------------------------------------------------------------- 1 | aside 2 | order -1 3 | 4 | @media ( min-width 769px ) 5 | aside 6 | left 0 7 | 8 | @media ( min-width 992px ) 9 | aside 10 | padding 0 15px 0 25px 11 | 12 | @media ( min-width 1440px ) 13 | aside 14 | margin-right 10px 15 | 16 | @media ( min-width 1912px ) 17 | article 18 | margin 0 2.5% 19 | -------------------------------------------------------------------------------- /source/css/_core/aside/layout/right.styl: -------------------------------------------------------------------------------- 1 | @media ( min-width 769px ) 2 | aside 3 | right 0 4 | 5 | @media ( min-width 992px ) 6 | aside 7 | padding 0 25px 0 15px 8 | 9 | @media ( min-width 1440px ) 10 | aside 11 | margin-left 10px 12 | 13 | @media ( min-width 1912px ) 14 | aside 15 | margin 0 2.5% 16 | -------------------------------------------------------------------------------- /source/css/_core/aside/toc.styl: -------------------------------------------------------------------------------- 1 | #toc-div 2 | display block 3 | .toc 4 | padding 10px 5 | margin unset 6 | list-style none 7 | .toc-child 8 | @media (min-width 769px) 9 | display none 10 | padding-left 1em 11 | list-style none 12 | .toc-item 13 | overflow hidden 14 | margin 2px 0 15 | white-space nowrap 16 | .has-active 17 | display block 18 | .toc-link 19 | display inline-block 20 | overflow-y auto 21 | width 100% 22 | position relative 23 | &::-webkit-scrollbar 24 | display none 25 | &::-ms-scrollbar 26 | display none 27 | scrollbar-width none 28 | @media (min-width 769px) 29 | &:hover .toc-number 30 | display none 31 | @media (min-width 769px) 32 | .active 33 | background-color var(--theme-highlight) 34 | color var(--theme-text-hover) 35 | .toc-number 36 | display none 37 | -------------------------------------------------------------------------------- /source/css/_core/base.styl: -------------------------------------------------------------------------------- 1 | html, body, label 2 | cursor var(--cursor-data) 3 3, default 3 | 4 | html, body 5 | position static 6 | 7 | body 8 | margin 0 9 | color var(--theme-text) 10 | background-image var(--body-background) 11 | background-color var(--theme-background) 12 | background-attachment fixed 13 | background-position 50% 0 14 | background-repeat no-repeat 15 | background-size cover 16 | font-family 'JetBrains Mono', 'Microsoft YaHei', '\5b8b\4f53', sans-serif 17 | 18 | main 19 | height 100vh 20 | width 100vw 21 | overflow auto 22 | overflow overlay 23 | box-sizing border-box 24 | 25 | h1, h2, h3, h4, h5, h6 26 | color var(--theme-text-light) 27 | margin-block-start .33em 28 | margin-block-end .23em 29 | padding-top .2em 30 | padding-bottom .2em 31 | 32 | p 33 | overflow visible 34 | 35 | a 36 | text-decoration none 37 | 38 | a, 39 | :is(strong, em) > a 40 | color var(--theme-highlight) 41 | padding 0 3px 42 | transition-duration .3s 43 | transition-property color, 44 | background-color, 45 | line-height, 46 | padding, 47 | border, 48 | opacity 49 | @media ( min-width 769px ) 50 | &:hover 51 | color var(--theme-text-hover) 52 | background-color var(--theme-highlight) 53 | &:active 54 | color var(--theme-text-hover) 55 | background-color var(--theme-subcolor) 56 | 57 | a:has(code) 58 | padding unset 59 | 60 | button 61 | background var(--theme-bg-soft) 62 | color var(--theme-text-light) 63 | font-family 'JetBrains Mono' 64 | border unset 65 | 66 | time 67 | font-family Bender 68 | 69 | code, pre 70 | font-family 'JetBrains Mono' 71 | code 72 | margin 0!important 73 | background-color var(--theme-bg-soft-hover) 74 | padding 0 3px!important 75 | pre 76 | margin 6px 0 77 | background-color transparent 78 | 79 | kbd 80 | color var(--theme-kbd-text) 81 | background-color var(--theme-subcolor) 82 | box-shadow 0 0.12em var(--theme-kbd-shadow) 83 | margin 0 2px 84 | border-radius 2px 85 | padding 0 3px 86 | font-family 'JetBrains Mono' 87 | 88 | em 89 | font-family Times, 'Times New Roman', 'FangSong', 'SimSun', serif 90 | strong em, em strong 91 | font-family 'JetBrains Mono', 'Microsoft YaHei', '\5b8b\4f53', sans-serif 92 | :not(a) > :is(strong, em) 93 | color var(--theme-light) 94 | :not(a) > :is(strong em, em strong) 95 | color var(--theme-stress) 96 | 97 | blockquote 98 | margin 1em 99 | border-left var(--theme-highlight) solid 5px 100 | padding 3px 20px 101 | background-color var(--theme-bg-soft) 102 | transition .3s 103 | blockquote 104 | margin 0 105 | padding-right 0 106 | &:hover 107 | background-color var(--theme-bg-soft-hover) 108 | 109 | li 110 | margin-block-start .2em 111 | margin-block-end .2em 112 | blockquote 113 | margin 0 114 | padding-right 0 115 | 116 | table 117 | border 0 118 | border-collapse collapse 119 | th 120 | color var(--theme-text-rev) 121 | background-color var(--theme-bg-light) 122 | border var(--theme-border-light) solid 1px 123 | padding 0 10px 124 | td 125 | padding 0 8px 126 | border var(--theme-td-border) solid 1px 127 | &:hover 128 | background-color var(--theme-td-hover) 129 | 130 | figure:not(.highlight), figcaption 131 | text-align center 132 | figcaption 133 | font-style italic 134 | 135 | a, button, input, textarea 136 | cursor var(--cursor) 3 3, pointer 137 | 138 | input 139 | cursor var(--cursor) 3 3, text 140 | user-select none 141 | font-family 'JetBrains Mono', 'Microsoft YaHei', '\5b8b\4f53', sans-serif 142 | 143 | .task-list 144 | padding-left 1em 145 | li 146 | display block 147 | margin-block .5em 148 | [type=checkbox] 149 | display none 150 | &::before 151 | content '' 152 | display inline-block 153 | position relative 154 | top 3px 155 | height .9em 156 | width .9em 157 | border-radius 3px 158 | background-color var(--theme-bg-soft) 159 | border 1px var(--theme-highlight) solid 160 | li[checked]::before 161 | content '\2713' 162 | line-height 1em 163 | text-align center 164 | color var(--theme-text-light) 165 | 166 | -------------------------------------------------------------------------------- /source/css/_core/color/atom-one.styl: -------------------------------------------------------------------------------- 1 | [theme-mode=dark] 2 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-keyword,.hljs-operator,.hljs-pattern-match{color:#f92672}.hljs-function,.hljs-pattern-match .hljs-constructor{color:#61aeee}.hljs-function .hljs-params{color:#a6e22e}.hljs-function .hljs-params .hljs-typing{color:#fd971f}.hljs-module-access .hljs-module{color:#7e57c2}.hljs-constructor{color:#e2b93d}.hljs-constructor .hljs-string{color:#9ccc65}.hljs-comment,.hljs-quote{color:#b18eb1;font-style:italic}.hljs-doctag,.hljs-formula{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} 3 | [theme-mode=light] 4 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#383a42;background:#fafafa}.hljs-comment,.hljs-quote{color:#a0a1a7;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e45649}.hljs-literal{color:#0184bb}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#50a14f}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#4078f2}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#c18401}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} 5 | -------------------------------------------------------------------------------- /source/css/_core/color/base.styl: -------------------------------------------------------------------------------- 1 | :root 2 | --dark-cursor url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGBAMAAAAS4vJ7AAAAElBMVEX///////////////////////+65XQCAAAABXRSTlPUzXppDN7WmLAAAAAZSURBVAjXY3ASVGEwDQ1mYA0NAGEQGyQGAC9SA/00lbgwAAAAAElFTkSuQmCC') 3 | --light-cursor url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxMAAAsTAQCanBgAAABESURBVBhXYwACHiCuAuKzUAxig8QYMoH4PxoGiTFcQRKA4StMQAIrYAZikApvMA8BGkASN4D4KxALAvFzIJ7CwMAwGwDaihLfRIaxUAAAAABJRU5ErkJggg') 4 | 5 | --theme-adm-warning #ffee22 6 | --theme-adm-note #22bbff 7 | --theme-adm-success #00c853 8 | --theme-adm-failure #C0392B 9 | --theme-adm-detail var(--theme-ex-header) 10 | -------------------------------------------------------------------------------- /source/css/_core/color/change.styl: -------------------------------------------------------------------------------- 1 | .social, #about 2 | text-shadow 2px 2px 4px var(--theme-text-rev) 3 | 4 | .navBlock > .navItemTitle 5 | text-shadow 1px 1px 2px var(--theme-text-rev), 1px 1px 2px var(--theme-text-rev) 6 | 7 | [theme-mode=light] 8 | .navItemTitle 9 | font-weight bold 10 | 11 | @media (min-width 769px) 12 | aside img:hover 13 | background-color var(--theme-bg-soft) 14 | 15 | button 16 | text-shadow 0 0 10px #000 17 | 18 | #color-mode 19 | @media (min-width 769px) 20 | &:hover::after 21 | transform rotate(-90deg) 22 | &::after 23 | transform rotate(-180deg) 24 | animation clockwise .3s 25 | @keyframes clockwise 26 | 0% 27 | transform rotate(-270deg) 28 | 100% 29 | transform rotate(-180deg) 30 | 31 | @media (min-width 769px) 32 | [theme-mode=dark] 33 | #color-mode:hover::after 34 | filter invert(1) 35 | 36 | #post-bg, 37 | h1, h2, h3, h4, h5, h6 38 | transition 1s 39 | 40 | @property --theme-bg-trans1 41 | syntax '' 42 | inherits true 43 | initial-value #fff 44 | 45 | #aside-block 46 | transition --theme-bg-trans1 1s 47 | -------------------------------------------------------------------------------- /source/css/_core/color/dark.styl: -------------------------------------------------------------------------------- 1 | :root[theme-mode=dark] 2 | --cursor-data var(--dark-cursor) 3 | --body-background var(--dark-background) 4 | 5 | --theme-highlight #2bf 6 | --theme-subcolor #fe2 7 | --theme-stress #C0392B 8 | 9 | --theme-bar-color-0 #fe2 10 | --theme-bar-color-1 #fe2a 11 | --theme-bar-color-2 #fe24 12 | --theme-bar-color-3 #fe22 13 | 14 | --theme-kbd-shadow #ba2 15 | --theme-kbd-text #000 16 | 17 | --theme-cursor #ccc 18 | --theme-cursor-bg #fff8 19 | 20 | --theme-text-hover #000 21 | 22 | --theme-text #c4c4c4 23 | --theme-text-light #fff 24 | --theme-text-rev #000 25 | 26 | --theme-background #141516 27 | --theme-bg-trans0 rgba(20, 21, 22, 0.95) 28 | --theme-bg-trans1 rgba(20, 21, 22, 0.8) 29 | --theme-bg-trans2 rgba(50, 52, 54, 0.8) 30 | --theme-bg-hover #000 31 | 32 | --theme-bg-light #fff 33 | --theme-bg-soft rgba(#fff, .05) 34 | --theme-bg-soft-hover rgba(#fff, .1) 35 | 36 | --theme-ex-header rgba(#fff, .3) 37 | 38 | --theme-btn-bg #d4d8dd 39 | 40 | --theme-border #fe2 41 | --theme-border-light #fff 42 | --theme-border-soft rgba(#fff, .1) 43 | 44 | --theme-unimportant #898989 45 | --theme-unimportant-trans #89898966 46 | --theme-unimportant-2 #535353 47 | 48 | --theme-td-border #2bf 49 | --theme-td-hover rgba(#2bf, .1) 50 | 51 | --theme-tag-bg #313131 52 | --theme-tag-count-bg #494949 53 | --theme-tag-border #313131 54 | 55 | --theme-loadingbar #fff 56 | --theme-loadingbar-fail #f00 57 | 58 | --theme-hide #000 59 | -------------------------------------------------------------------------------- /source/css/_core/color/light.styl: -------------------------------------------------------------------------------- 1 | :root[theme-mode=light] 2 | --cursor-data var(--light-cursor) 3 | --body-background var(--light-background) 4 | 5 | --theme-highlight #2bf 6 | --theme-subcolor #fe2 7 | --theme-stress #C0392B 8 | 9 | --theme-bar-color-0 #fe2 10 | --theme-bar-color-1 #fe2b 11 | --theme-bar-color-2 #fe28 12 | --theme-bar-color-3 #fe25 13 | 14 | --theme-kbd-shadow #ba2 15 | --theme-kbd-text #000 16 | 17 | --theme-cursor #333 18 | --theme-cursor-bg #0004 19 | 20 | --theme-text-hover #000 21 | 22 | --theme-text #222 23 | --theme-text-light #000 24 | --theme-text-rev #fff 25 | 26 | --theme-background #f4f5f6 27 | --theme-bg-trans0 rgba(#f4f5f6, 0.95) 28 | --theme-bg-trans1 rgba(#f4f5f6, 0.8) 29 | --theme-bg-trans2 rgba(#f4f5f6, .9) 30 | --theme-bg-hover #fff 31 | 32 | --theme-bg-light #000 33 | --theme-bg-soft rgba(#fff, .3) 34 | --theme-bg-soft-hover rgba(#fff, .6) 35 | 36 | --theme-ex-header #c0c0c0 37 | 38 | --theme-btn-bg #2a272d 39 | 40 | --theme-border #fe2 41 | --theme-border-light #000 42 | --theme-border-soft rgba(#000, .1) 43 | 44 | --theme-unimportant #767676 45 | --theme-unimportant-trans #76767666 46 | --theme-unimportant-2 #acacac 47 | 48 | --theme-td-border #2bf 49 | --theme-td-hover rgba(#2bf, .1) 50 | 51 | --theme-tag-bg #cecece 52 | --theme-tag-count-bg #bababa 53 | --theme-tag-border #cecece 54 | 55 | --theme-loadingbar #fff 56 | --theme-loadingbar-fail #f00 57 | 58 | --theme-hide #fff 59 | -------------------------------------------------------------------------------- /source/css/_core/core.styl: -------------------------------------------------------------------------------- 1 | @import 'base' 2 | @import 'cursor' 3 | @import 'scrollbar' 4 | 5 | @import 'aside/*' 6 | @import 'color/*' 7 | @import 'header/*' 8 | 9 | @import 'layout/flex_layout' 10 | @import 'layout/single_page' 11 | 12 | if hexo-config('aside.in_left') 13 | @import 'aside/layout/left' 14 | @import 'header/layout/left' 15 | else 16 | @import 'aside/layout/right' 17 | @import 'header/layout/right' 18 | -------------------------------------------------------------------------------- /source/css/_core/cursor.styl: -------------------------------------------------------------------------------- 1 | #cursor-outer 2 | z-index 65538 3 | position fixed 4 | transform translate3d(-50%, -50%, 0) 5 | height 36px 6 | width 36px 7 | border 1px solid var(--theme-cursor) 8 | border-radius 50% 9 | pointer-events none 10 | transition-duration .3s 11 | transition-property background-color, width, height 12 | #cursor-effect 13 | z-index 65538 14 | position fixed 15 | transform translate3d(-50%, -50%, 0) scale(0) 16 | height 80px 17 | width 80px 18 | border 4px solid var(--theme-cursor) 19 | border-radius 50% 20 | opacity 0 21 | pointer-events none 22 | -------------------------------------------------------------------------------- /source/css/_core/header/flex_layout.styl: -------------------------------------------------------------------------------- 1 | @media ( max-width 768px ) 2 | header 3 | left 0 4 | .navContent 5 | padding-left 0 6 | 7 | @media ( max-width 1023px ) 8 | main header 9 | width max(428px, 100% - 200px) 10 | max-width 100% 11 | position fixed 12 | nav 13 | max-width 428px 14 | height max-content 15 | min-height 100vh 16 | background-color var(--theme-bg-trans0) 17 | transform translateX(-100%) 18 | transition transform .6s 19 | pointer-events all 20 | .navItem 21 | padding .2em 4em 22 | .navContent 23 | overflow-y auto 24 | width 100% 25 | transition transform .6s 26 | .navBlock 27 | padding unset 28 | box-sizing border-box 29 | .navItemTitle 30 | padding 0 .2em 5px .2em 31 | color var(--theme-text-light) 32 | border-bottom 1px solid var(--theme-unimportant) 33 | .active > div > .navItemTitle::before 34 | border-color var(--theme-highlight) 35 | .expanded > nav 36 | transform translateX(0) 37 | .navItemList 38 | box-sizing border-box 39 | 40 | @media ( min-width 1024px ) 41 | header 42 | width 180px 43 | .navItem 44 | width 120px 45 | .navBlock 46 | position relative 47 | List-sum = 0 48 | for i in hexo-config('menu') 49 | List-sum += 3 50 | if hexo-config('search') && hexo-config('search.enable') 51 | List-sum += 2 52 | padding (30em / List-sum) 0 53 | .navItemTitle 54 | color var(--theme-text-light) 55 | &::before 56 | height 100% 57 | top 0 58 | box-sizing border-box 59 | 60 | @media ( min-width 1440px ) 61 | header 62 | width 240px 63 | .navItem 64 | width 150px 65 | 66 | @media ( min-width 1912px ) 67 | header 68 | width 310px 69 | -------------------------------------------------------------------------------- /source/css/_core/header/header.styl: -------------------------------------------------------------------------------- 1 | header 2 | pointer-events none 3 | top 0 4 | z-index 15 5 | height 100% 6 | font-family Bender 7 | display inline 8 | position sticky 9 | 10 | nav 11 | position relative 12 | height 100% 13 | white-space nowrap 14 | scrollbar-width none 15 | display flex 16 | flex-direction column 17 | justify-content center 18 | &::-webkit-scrollbar 19 | display none 20 | &::-ms-scrollbar 21 | display none 22 | li 23 | display block 24 | 25 | .navBlock 26 | transition unset 27 | position relative 28 | height 40px 29 | line-height 40px 30 | display inline-block 31 | width 100% 32 | &:hover 33 | background-color unset 34 | &:active 35 | background unset 36 | .navContent 37 | overflow visible 38 | margin unset 39 | position relative 40 | padding 0 41 | pointer-events all 42 | 43 | .navItem 44 | overflow visible 45 | position relative 46 | margin unset 47 | transition .6s 48 | .navItemTitle 49 | transition .3s 50 | width 100% 51 | box-sizing border-box 52 | overflow-wrap break-word 53 | white-space normal 54 | position relative 55 | display block 56 | .active > .navBlock > .navItemTitle 57 | color var(--theme-highlight) 58 | &::before 59 | content '' 60 | display block 61 | color var(--theme-highlight) 62 | border-color var(--theme-highlight) 63 | width 100% 64 | position absolute 65 | left 0 66 | -------------------------------------------------------------------------------- /source/css/_core/header/layout/left.styl: -------------------------------------------------------------------------------- 1 | header 2 | order 1 3 | 4 | @media ( min-width 769px ) 5 | header 6 | left 238px 7 | .navBtn 8 | left 1em 9 | 10 | @media ( max-width 1023px ) 11 | .navItemTitle:not(:only-child)::before 12 | content '' 13 | display inline-block 14 | height 6px 15 | width 6px 16 | border-right 2px solid var(--theme-highlight) 17 | border-top 2px solid var(--theme-highlight) 18 | margin 7px 7px 2px 2px 19 | transform rotate(45deg) 20 | 21 | @media ( min-width 1024px ) 22 | header 23 | left unset 24 | right 0 25 | .navContent 26 | display flex 27 | flex-direction column 28 | transform unset 29 | .navItem 30 | align-self end 31 | padding-right 1.2em 32 | .navItemTitle 33 | padding-left 4px 34 | .navBlock .navItemTitle:only-child::before 35 | border-right 4px solid 36 | .navContent .navBlock 37 | &::before 38 | content '' 39 | height 100% 40 | width 100% 41 | position absolute 42 | top 0 43 | right 2em 44 | &:hover > .navItemTitle 45 | margin-left -1em 46 | & > .navItemList 47 | right calc(100% + 2em) 48 | .navItemList 49 | right 100% 50 | .navItemTitle 51 | text-align right 52 | padding-right .8em 53 | padding-left .5em 54 | &::before 55 | content '' 56 | position absolute 57 | top 0 58 | left 0 59 | width calc(100% + 1em) 60 | height 100% 61 | a.navSecond > .navItemTitle 62 | padding-right 1em 63 | div.navSecond > .navItemTitle 64 | padding-right 2px 65 | .navSecond:not(a):hover 66 | left -.8em 67 | .navSecond:hover::after 68 | left .8em 69 | 70 | .navItemTitle:not(:only-child)::after 71 | box-sizing border-box 72 | content '' 73 | display inline-block 74 | height 6px 75 | width 6px 76 | border-left 2px solid var(--theme-highlight) 77 | border-bottom 2px solid var(--theme-highlight) 78 | margin 7px 2px 2px 7px 79 | transform rotate(45deg) 80 | 81 | @media ( min-width 1440px ) 82 | .navItem 83 | padding-right 2.25em 84 | 85 | @media ( min-width 1912px ) 86 | .navItem 87 | padding-right 5.25em 88 | -------------------------------------------------------------------------------- /source/css/_core/header/layout/right.styl: -------------------------------------------------------------------------------- 1 | @media ( min-width 769px ) 2 | header 3 | left 0 4 | 5 | @media ( min-width 1024px ) 6 | .navContent 7 | transform unset 8 | .navItem 9 | padding-left 1.2em 10 | .navItemTitle 11 | padding-right 5px 12 | .navBlock 13 | text-align right 14 | .navItemTitle:only-child::before 15 | border-left 4px solid 16 | left 0 17 | .navContent .navBlock 18 | &::before 19 | content '' 20 | height 100% 21 | width 100% 22 | position absolute 23 | top 0 24 | left 2em 25 | &:hover > .navItemTitle 26 | margin-left 1em 27 | & > .navItemList 28 | left calc(100% + 2em) 29 | .navItemList 30 | left 100% 31 | a.navSecond > .navItemTitle 32 | padding-left 1em 33 | div.navSecond > .navItemTitle 34 | padding-left 2px 35 | .navSecond:not(a):hover 36 | left .8em 37 | .navSecond:hover::after 38 | left -.8em 39 | 40 | @media ( min-width 1440px ) 41 | .navItem 42 | padding-left 2.25em 43 | 44 | @media ( min-width 1912px ) 45 | .navItem 46 | padding-left 5.25em 47 | 48 | .navItemTitle:not(:only-child)::before 49 | content '' 50 | display inline-block 51 | height 6px 52 | width 6px 53 | border-right 2px solid var(--theme-highlight) 54 | border-top 2px solid var(--theme-highlight) 55 | margin 7px 7px 2px 2px 56 | transform rotate(45deg) 57 | -------------------------------------------------------------------------------- /source/css/_core/header/navBtn.styl: -------------------------------------------------------------------------------- 1 | .navBtn 2 | transition transform .3s 3 | pointer-events all 4 | display none 5 | position fixed 6 | top 1em 7 | font-size 2em 8 | z-index 10 9 | .navBtnIcon 10 | z-index 10 11 | width 1em 12 | height 1em 13 | display block 14 | position relative 15 | .navBtnIconBar 16 | position absolute 17 | top 50% 18 | width 1em 19 | height 0.1em 20 | background-color var(--theme-btn-bg) 21 | text-indent 101% 22 | white-space nowrap 23 | overflow hidden 24 | transition transform ease-in-out 0.3s 25 | box-shadow 0 0 5px var(--theme-bg-hover), 0 0 5px var(--theme-bg-hover) 26 | .navBtnIconBar 27 | &:nth-child(1) 28 | left 0 29 | transform translate(0, -350%) 30 | &:nth-child(2) 31 | left 0 32 | transform translate(0, -50%) 33 | &:nth-child(3) 34 | right 0 35 | transform translate(0, 250%) 36 | 37 | .expanded .navBtnIconBar 38 | box-shadow unset 39 | &:nth-child(1) 40 | transform translate(0, -50%) rotateZ(45deg) scaleX(0.5) translate(-50%) 41 | &:nth-child(3) 42 | transform translate(0, -50%) rotateZ(45deg) scaleX(0.5) translate(50%) 43 | &:nth-child(2) 44 | transform translate(0, -50%) rotateZ(-45deg) 45 | 46 | @media ( max-width 1023px ) 47 | .navBtn 48 | display block 49 | left 1em 50 | .hide-btn.navBtn 51 | transform translateY(-2em) 52 | -------------------------------------------------------------------------------- /source/css/_core/header/navSecond.styl: -------------------------------------------------------------------------------- 1 | .navItemList 2 | display none 3 | overflow visible 4 | top 0 5 | text-align left 6 | background-color var(--theme-background) 7 | padding 0 8 | width 100% 9 | .navItem 10 | padding unset 11 | min-width max-content 12 | margin 0 13 | a 14 | min-width max-content 15 | padding 0 16 | display block 17 | width 100% 18 | line-height 40px 19 | &:hover > .navItemTitle 20 | color var(--theme-text-hover) 21 | 22 | @media ( max-width 1023px ) 23 | .navItemList 24 | padding-left 1em 25 | .expanded 26 | & > .navItemList 27 | display inline-block 28 | & > .navItemTitle::before 29 | transform rotate(135deg) 30 | 31 | @media ( min-width 1024px ) 32 | .navSecond 33 | left 0 34 | transition .3s 35 | position relative 36 | &:hover 37 | transition .3s 38 | &:hover::after 39 | content '' 40 | position absolute 41 | height 100% 42 | width 100% 43 | top 0 44 | .navItemList 45 | position absolute 46 | .navItem > div:hover > .navItemList 47 | display inline-block 48 | -------------------------------------------------------------------------------- /source/css/_core/layout/flex_layout.styl: -------------------------------------------------------------------------------- 1 | @media ( max-width 768px ) 2 | main 3 | padding 0 12px 4 | article 5 | border none 6 | width 100% 7 | max-height none 8 | #post-bg 9 | padding 10px 10px 0 10px 10 | .highlight, blockquote 11 | margin 1em 0 12 | aside 13 | position static 14 | width 100% 15 | height auto 16 | padding 0 17 | h1 18 | font-size xx-large 19 | text-align center 20 | margin 0 21 | footer 22 | text-align center 23 | padding 10px 0 24 | position static 25 | #paginator 26 | margin 20px 0 0 0 27 | a, span 28 | margin 5px 5px 0 0 29 | #post-index 30 | margin 0 31 | #logo 32 | height 0 33 | margin 0 34 | img 35 | opacity .05 36 | position fixed 37 | bottom -50px 38 | left -46% 39 | pointer-events none 40 | #total 41 | text-align center 42 | margin 0 43 | .total-title 44 | font-size medium 45 | #total-archives 46 | width auto 47 | .total-title 48 | display inline-block 49 | #to-index 50 | bottom 56px 51 | #to-top 52 | bottom 16px 53 | #post-index 54 | margin 16px 10px 0 10px 55 | #archive-flex 56 | flex-direction column 57 | #archive-aside 58 | order 1 59 | #Categories 60 | margin 10px 61 | #cursor-container 62 | display none 63 | #Archives 64 | margin 0 65 | time 66 | color var(--theme-text-light) 67 | padding 0 68 | .control 69 | width 55px 70 | @media ( min-width 769px ) 71 | main 72 | display flex 73 | justify-content space-between 74 | article 75 | width calc(95% - 212px) 76 | #total-archives .total-number 77 | font-size 34px 78 | #to-index 79 | display none 80 | aside 81 | top 0 82 | width 170px 83 | h1 84 | font-size xx-large 85 | img 86 | transition background-color 1s 87 | &:hover 88 | background-color var(--theme-bg-soft-hover) 89 | #description p 90 | font-size small 91 | #archive-aside 92 | position sticky 93 | max-width 36% 94 | 95 | @media ( min-width 1024px ) 96 | article 97 | width calc(100% - 412px) 98 | aside 99 | width 190px 100 | h1 101 | font-size 45px 102 | #total-archives .total-number 103 | font-size 40px 104 | #description p 105 | font-size medium 106 | 107 | @media ( min-width 1440px ) 108 | article 109 | width calc(100% - 520px) 110 | aside 111 | width 230px 112 | h1 113 | font-size 50px 114 | #total-archives 115 | .total-title 116 | font-size 32px 117 | .total-number 118 | font-size 48px 119 | #total-tags, #total-categories 120 | font-size 23px 121 | .recent-post img 122 | width 90% 123 | margin 0 auto 124 | display block 125 | position relative 126 | @media ( min-width 1912px ) 127 | article 128 | width calc(95% - 630px) 129 | aside 130 | width 270px 131 | h1 132 | font-size 55px 133 | #total-archives .total-title 134 | font-size 37px 135 | #total-tags, #total-categories 136 | font-size 28px 137 | .search-pop-overlay .popup 138 | left 65% 139 | .recent-post img 140 | width 80% 141 | -------------------------------------------------------------------------------- /source/css/_core/layout/single_page.styl: -------------------------------------------------------------------------------- 1 | @media ( max-width 1023px ) 2 | :is(.moving, .up) nav 3 | overflow visible 4 | .moving 5 | pointer-events none 6 | .navBtn 7 | pointer-events none 8 | .navContent 9 | overflow visible 10 | 11 | :is(.up, .moving) main 12 | overflow hidden 13 | 14 | .up 15 | article 16 | margin-top 50px 17 | .closed 18 | .navBtn 19 | transform translateY(-.5em) 20 | .navContent 21 | overflow visible 22 | 23 | @media ( max-width 768px ) 24 | .up article 25 | margin-top 60px 26 | -------------------------------------------------------------------------------- /source/css/_core/scrollbar.styl: -------------------------------------------------------------------------------- 1 | @media ( min-width 769px) 2 | main 3 | -ms-scrollbar-base-color var(--theme-bar-color-2) 4 | -ms-scrollbar-track-color var(--theme-bar-color-3) 5 | scrollbar-color var(--theme-bar-color-0) var(--theme-bar-color-2) 6 | scrollbar-width thin 7 | scrollbar-gutter stable 8 | ::-webkit-scrollbar 9 | width 6px 10 | height 6px 11 | ::-webkit-scrollbar-thumb 12 | background-color var(--theme-bar-color-2) 13 | border-radius .25em 14 | ::-webkit-scrollbar-track 15 | background-color var(--theme-bar-color-3) 16 | ::-webkit-scrollbar-thumb:hover 17 | background-color var(--theme-bar-color-1) 18 | ::-webkit-scrollbar-thumb:window-inactive 19 | background-color var(--theme-bar-color-3) 20 | -------------------------------------------------------------------------------- /source/css/_custom/custom.styl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/css/_custom/custom.styl -------------------------------------------------------------------------------- /source/css/_modules/canvas_dust.styl: -------------------------------------------------------------------------------- 1 | #canvas-dust 2 | z-index -65536 3 | pointer-events none 4 | position fixed 5 | top 0 6 | left 0 7 | -------------------------------------------------------------------------------- /source/css/_modules/cards/admonition.styl: -------------------------------------------------------------------------------- 1 | .admonition > .ex-header:nth-child(2) 2 | margin-right 2px 3 | 4 | .i-adm 5 | display inline-block 6 | height 20px 7 | width 20px 8 | margin-right 2px 9 | background var(--theme-text-light) 10 | 11 | for name in note warning success failure detail 12 | if name != detail 13 | .i-{name} 14 | mask-image var(--adm-icon- + name) 15 | -webkit-mask-image var(--adm-icon- + name) 16 | .admonition.adm-{name} 17 | --ex-color var(--theme-adm- + name) 18 | 19 | @css { 20 | :root { 21 | --adm-icon-note: url('data:image/svg+xml;charset=utf-8,'); 22 | --adm-icon-success: url('data:image/svg+xml;charset=utf-8,'); 23 | --adm-icon-warning: url('data:image/svg+xml;charset=utf-8,'); 24 | --adm-icon-failure: url('data:image/svg+xml;charset=utf-8,'); 25 | } 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /source/css/_modules/cards/hide.styl: -------------------------------------------------------------------------------- 1 | .hide 2 | transition .1s 3 | background var(--theme-hide) 4 | padding 5px 5 | p 6 | display inline 7 | code 8 | box-sizing border-box 9 | &:hover 10 | code 11 | border 1px solid var(--theme-border-soft) 12 | &:not(:hover) 13 | color var(--theme-hide) 14 | code 15 | border 1px solid transparent 16 | background var(--theme-hide) 17 | strong, em, p, i, a 18 | color var(--theme-hide) 19 | strong, em, p, i, a, span 20 | transition .1s 21 | -------------------------------------------------------------------------------- /source/css/_modules/cards/link-card.styl: -------------------------------------------------------------------------------- 1 | @property --card-border 2 | syntax '' 3 | inherits true 4 | initial-value transparent 5 | 6 | .link-card 7 | display inline-block 8 | width 320px 9 | padding unset 10 | margin .5em 1em 11 | position relative 12 | z-index 1 13 | &:hover 14 | background-color var(--theme-bg-soft-hover) 15 | &::before 16 | --card-border var(--theme-highlight) 17 | .link-main 18 | border-left 2px solid var(--theme-highlight) 19 | img 20 | max-height 100% 21 | max-width 100% 22 | display block 23 | border-bottom 1px solid var(--theme-border-soft) 24 | margin-bottom -1px 25 | 26 | .link-card::before 27 | content '' 28 | position absolute 29 | left 0 30 | top 0 31 | width 100% 32 | height 100% 33 | transition --card-border .3s 34 | box-shadow 0 0 5px inset var(--card-border) 35 | 36 | .link-main 37 | transition border-color .3s 38 | background-color var(--theme-bg-soft) 39 | border-left 2px solid var(--theme-text-light) 40 | border-block inset 1px solid var(--theme-border-soft) 41 | display flex 42 | align-items center 43 | height 4em 44 | padding .5em 45 | .link-ico 46 | height 50px 47 | width 50px 48 | img 49 | border-radius 50% 50 | &.link-full 51 | width 100% 52 | display flex 53 | justify-content center 54 | .link-data 55 | padding 0 .5em 56 | width calc(100% - 50px) 57 | box-sizing border-box 58 | &.link-full 59 | width 100% 60 | .link-title 61 | color var(--theme-text-light) 62 | font-size 1.2em 63 | .link-descr 64 | color var(--theme-text) 65 | font-family BenderLight, FangSong, sans-serif 66 | height 36px 67 | overflow hidden 68 | text-overflow ellipsis 69 | display: -webkit-box 70 | -webkit-line-clamp 2 71 | -webkit-box-orient vertical 72 | &.link-full 73 | height 54px 74 | -webkit-line-clamp 3 75 | 76 | .link-main.link-simple 77 | height 3em 78 | 79 | .link-background 80 | position relative 81 | z-index -1 82 | -------------------------------------------------------------------------------- /source/css/_modules/comments/comments.styl: -------------------------------------------------------------------------------- 1 | $comment-count = 0 2 | 3 | if hexo-config('gitalk.enable') 4 | $comment-count = $comment-count + 1 5 | @import 'gitalk' 6 | 7 | if hexo-config('valine.enable') 8 | $comment-count = $comment-count + 1 9 | @import 'valine' 10 | 11 | if hexo-config('waline.enable') 12 | $comment-count = $comment-count + 1 13 | @import 'waline' 14 | 15 | if $comment-count > 0 16 | #comments 17 | border-top var(--theme-border) solid 2px 18 | 19 | if $comment-count > 1 20 | @import 'selector' 21 | -------------------------------------------------------------------------------- /source/css/_modules/comments/gitalk.styl: -------------------------------------------------------------------------------- 1 | .gt-container 2 | box-sizing border-box 3 | font-size 16px 4 | -webkit-box-sizing border-box 5 | * 6 | box-sizing border-box 7 | -webkit-box-sizing border-box 8 | a.is--active 9 | color var(--theme-unimportant-2) 10 | pointer-events none 11 | &:hover 12 | background unset 13 | color var(--theme-unimportant-2) 14 | .hide 15 | display none !important 16 | .gt-svg 17 | position relative 18 | top -2px 19 | display inline-block 20 | width 1em 21 | height 1em 22 | vertical-align sub 23 | transition .3s 24 | svg 25 | width 100% 26 | height 100% 27 | .gt-ico 28 | display inline-block 29 | &.gt-ico-text 30 | margin-left .3125em 31 | .gt-header-controls-tip:hover 32 | color var(--theme-text-hover) 33 | .gt-ico-github 34 | position relative 35 | top 4px 36 | .gt-svg 37 | width 42px 38 | height 42px 39 | fill var(--theme-text) 40 | &:hover 41 | fill var(--theme-text-hover) 42 | .gt-spinner 43 | position relative 44 | &::before 45 | position absolute 46 | top 3px 47 | box-sizing border-box 48 | margin-top -.1875em 49 | margin-left -.375em 50 | width .75em 51 | height .75em 52 | border 1px solid var(--theme-text-hover) 53 | border-top-color var(--theme-highlight) 54 | border-radius 50% 55 | content '' 56 | animation gt-kf-rotate .6s linear infinite 57 | -webkit-box-sizing border-box 58 | -webkit-animation gt-kf-rotate .6s linear infinite 59 | .gt-loader 60 | position relative 61 | display inline-block 62 | width 1.75em 63 | height 1.75em 64 | border 1px solid var(--theme-unimportant) 65 | border-radius 50% 66 | font-style normal 67 | line-height 1.75em 68 | animation ease gt-kf-rotate 1.5s infinite 69 | -webkit-animation ease gt-kf-rotate 1.5s infinite 70 | &:before 71 | position absolute 72 | top 0 73 | left 50% 74 | display block 75 | margin-top -.1875em 76 | margin-left -.1875em 77 | width .375em 78 | height .375em 79 | border-radius 50% 80 | background-color var(--theme-unimportant) 81 | content '' 82 | .gt-avatar 83 | display inline-block 84 | width 3.125em 85 | height 3.125em 86 | .gt-avatar-github 87 | width 3em 88 | height 3em 89 | &:hover .gt-svg 90 | fill var(--theme-text-hover) 91 | .gt-btn 92 | &:hover 93 | border 1px solid var(--theme-border) 94 | background-color var(--theme-bg-soft-hover) 95 | color var(--theme-subcolor) 96 | transition .3s 97 | &.is--disable 98 | opacity .5 99 | cursor not-allowed 100 | .gt-btn-text 101 | font-weight 400 102 | .gt-btn-loading 103 | position relative 104 | display inline-block 105 | margin-left .5em 106 | width .75em 107 | height 1em 108 | vertical-align top 109 | .gt-btn-login 110 | margin-right 0 111 | .gt-error 112 | margin .625em 113 | color var(--theme-stress) 114 | text-align center 115 | .gt-initing 116 | padding 1.25em 0 117 | text-align center 118 | .gt-initing-text 119 | margin .625em auto 120 | font-size 92% 121 | .gt-no-init 122 | padding 1.25em 0 123 | text-align center 124 | .gt-link 125 | border-bottom 1px dotted var(--theme-highlight) 126 | .gt-meta 127 | position relative 128 | z-index 10 129 | margin 1.25em 0 130 | padding 1em 0 131 | border-bottom 1px solid var(--theme-unimportant-2) 132 | font-size 1em 133 | &:after 134 | clear both 135 | .gt-counts 136 | margin 0 .625em 0 0 137 | .gt-user 138 | float right 139 | margin 0 140 | font-size 92% 141 | .gt-ico 142 | margin 0 0 0 .3125em 143 | svg 144 | fill var(--theme-text) 145 | .gt-user-pic 146 | margin-right .5em 147 | width 16px 148 | height 16px 149 | vertical-align top 150 | .gt-user-inner 151 | display inline-block 152 | .gt-ico-arrdown .gt-svg 153 | transform rotate(180deg) 154 | &.is--poping .gt-ico-arrdown .gt-svg 155 | transform rotate(0) 156 | .gt-version 157 | color var(--theme-text) 158 | font-size small 159 | .gt-copyright 160 | margin 0 .7em .5em 161 | padding-top .5em 162 | border-top 1px solid var(--theme-unimportant-2) 163 | .gt-link-project 164 | margin-right 1px 165 | .gt-popup 166 | position absolute 167 | top 2.4em 168 | right 0 169 | display inline-block 170 | padding .625em 0 171 | border 1px solid var(--theme-unimportant-2) 172 | background var(--theme-background) 173 | font-size .875em 174 | .gt-action 175 | position relative 176 | display block 177 | margin .3em .7em 178 | text-decoration none 179 | letter-spacing 1px 180 | &.is--active 181 | &:before 182 | position absolute 183 | top .6em 184 | left -.4em 185 | width .25em 186 | height .25em 187 | background var(--theme-highlight) 188 | content '' 189 | .gt-header 190 | position relative 191 | display -webkit-box 192 | display -ms-flexbox 193 | display flex 194 | .gt-header-comment 195 | flex 1 196 | margin-left 1.25em 197 | -webkit-box-flex 1 198 | -ms-flex 1 199 | .gt-header-textarea:hover 200 | border 1px solid var(--theme-border) 201 | background-color var(--theme-bg-soft-hover) 202 | .gt-header-preview 203 | overflow auto 204 | padding .75em 205 | min-height 72px 206 | width 100% 207 | border 1px solid var(--theme-border-light) 208 | border-radius 5px 209 | background-color var(--theme-bg-soft) 210 | transition .3s 211 | &:hover 212 | padding .75em 213 | border 1px solid var(--theme-border) 214 | border-radius 5px 215 | background-color var(--theme-bg-soft-hover) 216 | p 217 | width fit-content 218 | .gt-header-controls 219 | position relative 220 | margin .75em 0 0 221 | &:after 222 | clear both 223 | &.gt-input-focused 224 | position relative 225 | &:after 226 | position fixed 227 | top 0 228 | right 0 229 | bottom 0% 230 | left 0 231 | z-index 9999 232 | background var(--theme-background) 233 | content '' 234 | opacity .6 235 | .gt-header-comment 236 | z-index 10000 237 | &:after 238 | transition .3s 239 | .gt-comments 240 | padding-top 1.25em 241 | padding-bottom 1.25em 242 | .gt-comments-null 243 | text-align center 244 | .gt-comments-controls 245 | margin 1.25em 0 246 | text-align center 247 | .gt-comment 248 | position relative 249 | display -webkit-box 250 | display -ms-flexbox 251 | display flex 252 | padding .625em 0 253 | .gt-comment-content 254 | flex 1 255 | overflow auto 256 | margin-left 1.25em 257 | padding .75em 1em 258 | padding-left 20px 259 | border-left #fe2 solid 3px 260 | background-color var(--theme-bg-soft) 261 | color var(--theme-text) 262 | transition .3s 263 | transition .3s 264 | -webkit-box-flex 1 265 | -ms-flex 1 266 | &:hover 267 | border-color var(--theme-highlight) 268 | background-color var(--theme-bg-soft-hover) 269 | &::before 270 | background linear-gradient(180deg, transparent, var(--theme-bg-trans0)) 271 | &::after 272 | background var(--theme-bg-trans0) 273 | p 274 | color var(--theme-text-light) 275 | .gt-comment-block-1 276 | float right 277 | width 2em 278 | height 1.375em 279 | .gt-comment-block-2 280 | float right 281 | width 4em 282 | height 1.375em 283 | .gt-comment-text, .gt-comment-date 284 | margin-left .5em 285 | color var(--theme-text) 286 | .gt-comment-body 287 | .email-hidden-toggle a 288 | display inline-block 289 | padding 0 9px 290 | height 12px 291 | border-radius 1px 292 | vertical-align middle 293 | font-weight 600 294 | font-size 12px 295 | line-height 6px 296 | .email-hidden-reply 297 | display none 298 | white-space pre-wrap 299 | .email-signature-reply 300 | margin 15px 0 301 | padding 0 15px 302 | border-left 4px solid var(--theme-border-light) 303 | color var(--theme-unimportant-2) 304 | &.expanded 305 | display block 306 | 307 | a 308 | .gt-ico 309 | fill var(--theme-highlight) 310 | &:hover .gt-ico 311 | fill var(--theme-text-hover) 312 | 313 | @media (max-width 479px) 314 | .gt-container .gt-avatar 315 | width 2em 316 | height 2em 317 | .gt-container .gt-avatar-github 318 | width 1.875em 319 | height 1.875em 320 | .gt-container .gt-header-comment 321 | margin-left .875em 322 | .gt-container .gt-header-controls 323 | margin 0 324 | .gt-container .gt-header-controls-tip 325 | display none 326 | .gt-container .gt-header-controls .gt-btn 327 | float none 328 | margin .75em 0 0 329 | width 100% 330 | .gt-container .gt-comment-content 331 | margin-left .875em 332 | padding .625em .75em 333 | 334 | .gt-container 335 | .gt-avatar img 336 | width 100% 337 | height auto 338 | border-radius 50% 339 | .gt-btn 340 | display inline-block 341 | padding .75em 1.25em 342 | outline none 343 | border 1px solid var(--theme-border-light) 344 | border-radius 5px 345 | background-color var(--theme-bg-soft) 346 | color var(--theme-text-light) 347 | white-space nowrap 348 | font-size .75em 349 | line-height 1 350 | transition .3s 351 | .gt-header-textarea 352 | display block 353 | box-sizing border-box 354 | padding .75em 355 | min-height 5.125em 356 | max-height 15em 357 | width 100% 358 | outline none 359 | border 1px solid var(--theme-border-light) 360 | border-radius 5px 361 | background-color var(--theme-bg-soft) 362 | color var(--theme-text-light) 363 | word-wrap break-word 364 | font-size .875em 365 | font-family 'JetBrains Mono', 'Microsoft YaHei', sans-serif 366 | resize vertical 367 | transition .3s 368 | -webkit-box-sizing border-box 369 | .gt-header-controls-tip 370 | vertical-align sub 371 | font-size .875em 372 | .gt-header-controls .gt-btn 373 | float right 374 | margin-left 1.25em 375 | &:after 376 | position fixed 377 | top 0 378 | right 0 379 | bottom 100% 380 | left 0 381 | content '' 382 | opacity 0 383 | .gt-comment-header 384 | position relative 385 | margin-bottom .5em 386 | font-size .875em 387 | 388 | .gt-container .gt-meta:before, .gt-container .gt-meta:after, .gt-container .gt-header-controls:before, .gt-container .gt-header-controls:after 389 | display table 390 | content ' ' 391 | 392 | .gt-comment-like, .gt-comment-reply 393 | fill var(--theme-highlight) 394 | &:hover 395 | fill var(--theme-text-hover) 396 | 397 | .gt-container .gt-comment-like 398 | height 1.375em 399 | 400 | .gt-container .gt-comment-edit, .gt-container .gt-comment-reply 401 | position absolute 402 | height 1.375em 403 | 404 | .gt-container .gt-comment-edit:hover 405 | top 0 406 | 407 | .gt-container .gt-comment-edit, .gt-container .gt-comment-reply 408 | top 0 409 | right 0 410 | 411 | @keyframes gt-kf-rotate 412 | 0% 413 | transform rotate(0) 414 | -webkit-transform rotate(0) 415 | 100% 416 | transform rotate(360deg) 417 | transform rotate(360deg) 418 | -webkit-transform rotate(360deg) 419 | -webkit-transform rotate(360deg) 420 | 421 | @keyframes gt-kf-rotate 422 | 0% 423 | transform rotate(0) 424 | -webkit-transform rotate(0) 425 | 100% 426 | transform rotate(360deg) 427 | transform rotate(360deg) 428 | -webkit-transform rotate(360deg) 429 | -webkit-transform rotate(360deg) 430 | -------------------------------------------------------------------------------- /source/css/_modules/comments/selector.styl: -------------------------------------------------------------------------------- 1 | .selector 2 | margin-top 2em 3 | display flex 4 | justify-content space-around 5 | background var(--theme-bg-soft) 6 | position relative 7 | &::after 8 | content '' 9 | position absolute 10 | left 0 11 | top 100% 12 | height 100% 13 | width 100% 14 | background linear-gradient(180deg, var(--theme-bg-soft), transparent) 15 | button 16 | transition .3s 17 | height 40px 18 | flex-grow 1 19 | border-left 1px solid var(--theme-border) 20 | display flex 21 | align-items center 22 | &.active 23 | background transparent 24 | &:hover:not(.active) 25 | background var(--theme-bg-soft-hover) 26 | &::after 27 | display block 28 | width 100% 29 | text-align center 30 | font-size 16px 31 | &:last-child 32 | border-right 1px solid var(--theme-border) 33 | 34 | .valine-sel::after 35 | content "Valine" 36 | 37 | .gitalk-sel::after 38 | content "Gitalk" 39 | 40 | .waline-sel::after 41 | content "Waline" 42 | 43 | .artalk-sel::after 44 | content "Artalk" 45 | -------------------------------------------------------------------------------- /source/css/_modules/comments/valine.styl: -------------------------------------------------------------------------------- 1 | #valine 2 | color var(--theme-text-light) 3 | padding 10px 0 4 | * 5 | line-height normal 6 | code 7 | font-family 'JetBrains Mono' 8 | .vwrap 9 | background-color var(--theme-bg-soft) 10 | transition .3s 11 | &:hover 12 | background-color var(--theme-bg-soft-hover) 13 | border-color var(--theme-border) 14 | .vheader .vinput 15 | line-height 1 16 | border-bottom-style solid 17 | &:focus 18 | color var(--theme-highlight) 19 | border-bottom-color var(--theme-border) 20 | .vicon:hover 21 | background-color unset 22 | .vsubmit:hover 23 | color var(--theme-subcolor) 24 | border-color var(--theme-border) 25 | background-color var(--theme-bg-soft-hover) 26 | .vsys 27 | background-color transparent 28 | .vmeta 29 | margin 3px 0 3px 3px 30 | .vmeta .vat 31 | transition .3s 32 | color var(--theme-subcolor) 33 | padding-inline 3px 34 | .vmeta .vnick 35 | margin-left 3px 36 | .vat:hover 37 | color var(--theme-text-rev) 38 | background-color var(--theme-highlight) 39 | .vcontent 40 | margin-left 3px 41 | color var(--theme-text) 42 | border-left var(--theme-subcolor) solid 3px 43 | padding 0.625em 0 0.625em 20px 44 | background-color var(--theme-bg-soft) 45 | transition .3s 46 | &:hover 47 | border-color var(--theme-highlight) 48 | background-color var(--theme-bg-soft-hover) 49 | &::before 50 | background linear-gradient(180deg, transparent, var(--theme-bg-trans0)) 51 | &::after 52 | background var(--theme-bg-trans0) 53 | p 54 | color var(--theme-text-light) 55 | .vquote 56 | margin-left 3px 57 | .vempty 58 | display: none !important 59 | a, button, .vicon, .vnick, .vat 60 | cursor var(--cursor-data) 3 3, pointer 61 | a 62 | color var(--theme-highlight) 63 | &:hover 64 | color var(--theme-text-hover) 65 | #veditor 66 | color var(--theme-text-light) 67 | font-family 'JetBrains Mono' 68 | -------------------------------------------------------------------------------- /source/css/_modules/comments/waline.styl: -------------------------------------------------------------------------------- 1 | #waline 2 | --waline-theme-color var(--theme-highlight) 3 | --waline-active-color var(--theme-text-hover) 4 | --waline-color var(--theme-text) 5 | --waline-bgcolor var(--theme-bg-soft) 6 | --waline-bgcolor-hover var(--theme-bg-soft-hover) 7 | 8 | button 9 | transition .3s 10 | .wl-actions > :first-child 11 | display flex 12 | a, .wl-action, .wl-sort li, .wl-text-number, button 13 | user-select none 14 | cursor var(--cursor-data) 3 3, pointer 15 | .wl-btn 16 | color var(--theme-text-light) 17 | background var(--theme-bg-soft) 18 | border var(--theme-border-light) 1px solid 19 | cursor var(--cursor-data) 3 3, pointer 20 | &:hover 21 | color var(--theme-subcolor) 22 | border var(--theme-border) 1px solid 23 | background var(--theme-bg-soft-hover) 24 | -------------------------------------------------------------------------------- /source/css/_modules/expand.styl: -------------------------------------------------------------------------------- 1 | .expand-box 2 | --ex-color var(--theme-ex-header) 3 | 4 | margin 1em 5 | border-left 5px solid 6 | border-color var(--ex-color) 7 | & > .ex-header::before 8 | content '' 9 | display block 10 | position absolute 11 | top 0 12 | left 0 13 | width 100% 14 | height 100% 15 | background-color var(--ex-color) 16 | opacity .6 17 | 18 | .ex-header 19 | position relative 20 | padding 7px 0px 7px 8px 21 | overflow hidden 22 | min-height 20px 23 | user-select none 24 | display flex 25 | justify-content space-between 26 | align-items center 27 | color var(--theme-text-light) 28 | &:focus-visible 29 | outline #fff auto 1px 30 | .ex-title 31 | z-index 1 32 | flex-grow 1 33 | .i-status 34 | font-style normal 35 | display inline-block 36 | width 20px 37 | height 20px 38 | margin-right 5px 39 | &::before 40 | content '' 41 | display block 42 | height 6px 43 | width 6px 44 | border-top 2px solid var(--theme-text-light) 45 | border-right 2px solid var(--theme-text-light) 46 | margin 7px 7px 5px 5px 47 | 48 | 49 | .ex-content 50 | position relative 51 | overflow-y hidden 52 | max-height 0 53 | padding-left 20px 54 | background-color var(--theme-bg-soft) 55 | &:hover 56 | background-color var(--theme-bg-soft-hover) 57 | 58 | .open > .ex-content 59 | transition max-height .5s cubic-bezier(.5, 0, 1, 0), background .3s 60 | max-height 10000px 61 | .open > div > .i-status 62 | transform rotate(135deg) 63 | transition transform .2s ease 64 | 65 | .fold > .ex-content 66 | transition max-height .5s cubic-bezier(0, 1, 0, 1) -.1s, background .3s 67 | max-height 0 68 | .fold > div > .i-status 69 | transform rotate(45deg) 70 | transition transform .2s ease 71 | -------------------------------------------------------------------------------- /source/css/_modules/lightgallery.styl: -------------------------------------------------------------------------------- 1 | .lg-container[role='dialog'] .lg-outer.lg-css3 * 2 | cursor var(--dark-cursor) 3 3, grab 3 | .lg-container 4 | position absolute 5 | z-index 65537 6 | -------------------------------------------------------------------------------- /source/css/_modules/modules.styl: -------------------------------------------------------------------------------- 1 | if hexo-config('canvas_dust') 2 | @import 'canvas_dust' 3 | 4 | if hexo-config('search.enable') 5 | @import 'search/base' 6 | if hexo-config('aside.in_left') 7 | @import 'search/left' 8 | else 9 | @import 'search/right' 10 | 11 | if hexo-config('pjax.enable') 12 | @import 'pjax' 13 | 14 | @import 'cards/*' 15 | 16 | @import 'expand' 17 | 18 | @import 'social' 19 | 20 | @import 'comments/comments' 21 | 22 | @import 'lightgallery' 23 | -------------------------------------------------------------------------------- /source/css/_modules/pjax.styl: -------------------------------------------------------------------------------- 1 | .loading 2 | --loadingbar var(--theme-loadingbar) 3 | 4 | .loading.fail 5 | --loadingbar var(--theme-loadingbar-fail) 6 | 7 | .loading 8 | opacity 0 9 | transition opacity .3s 10 | &.reset .loadingBar 11 | transition unset 12 | .loadingBar 13 | z-index 100 14 | position fixed 15 | top 0 16 | border-bottom 1px solid var(--loadingbar) 17 | width 50% 18 | transition transform .6s 19 | &::before 20 | width 20px 21 | &::after 22 | width 1px 23 | .left 24 | left 0 25 | transform-origin left 26 | &::before 27 | box-shadow 10px 0 15px 1px var(--loadingbar) 28 | right 0 29 | &::after 30 | box-shadow .5px 0 8px 2px var(--loadingbar), .5px 0 2px 1px var(--loadingbar) 31 | right 0 32 | .right 33 | right 0 34 | transform-origin right 35 | &::before 36 | box-shadow -10px 0 15px 1px var(--loadingbar) 37 | left 0 38 | &::after 39 | box-shadow -.5px 0 8px 2px var(--loadingbar), -.5px 0 2px 1px var(--loadingbar) 40 | left 0 41 | 42 | .loadingBar::before, 43 | .loadingBar::after 44 | content '' 45 | display block 46 | position absolute 47 | top 0 48 | height 1px 49 | 50 | .pjax-out 51 | pointer-events none 52 | position absolute!important 53 | animation .6s pjax-animate-out 54 | .pjax-in 55 | pointer-events none 56 | position absolute!important 57 | animation .6s pjax-animate-in 58 | 59 | :is(#paginator, .bottom-btn):is(.pjax-in, .pjax-out) 60 | visibility hidden 61 | pointer-events none 62 | 63 | @keyframes pjax-animate-in 64 | 0% 65 | opacity 0 66 | 100% 67 | opacity 1 68 | 69 | @keyframes pjax-animate-out 70 | 0% 71 | opacity 1 72 | 100% 73 | opacity 0 74 | -------------------------------------------------------------------------------- /source/css/_modules/search/base.styl: -------------------------------------------------------------------------------- 1 | @import 'single_page' 2 | 3 | #search-header 4 | pointer-events all 5 | position relative 6 | input 7 | padding unset 8 | box-sizing border-box 9 | color var(--theme-text-light) 10 | position relative 11 | &::placeholder 12 | transition .3s 13 | font-size 15px 14 | height 40px 15 | background-color unset 16 | border unset 17 | outline none 18 | width 100% 19 | .navItemTitle 20 | overflow hidden 21 | &:hover 22 | margin unset 23 | &::before, &::after 24 | display block 25 | content '' 26 | position absolute 27 | 28 | #search-holder 29 | @media (min-width: 1024px) 30 | height 40px 31 | @media (max-width: 1023px) 32 | height 2.82em 33 | display none 34 | 35 | .search #search-holder 36 | display block 37 | 38 | main:not(.up) .search #search-header 39 | position absolute 40 | top 40px 41 | input 42 | animation get-out .6s 43 | 44 | @media ( min-width 1024px ) 45 | .search-popup 46 | background-color var(--theme-bg-trans0) 47 | #search-header .navItemTitle 48 | &::before 49 | z-index -2 50 | &::after 51 | top 0 52 | width 0 53 | height 100% 54 | transition .3s 55 | z-index -1 56 | background-color var(--theme-highlight) 57 | &:hover 58 | input::placeholder 59 | transition .3s 60 | color var(--theme-text-hover) 61 | &::after 62 | transition .3s 63 | width 100% 64 | background-color var(--theme-highlight) 65 | 66 | .search-popup 67 | scrollbar-width thin 68 | pointer-events all 69 | z-index 20 70 | transition transform .6s 71 | overflow-wrap anywhere 72 | position fixed 73 | top 90px 74 | height calc(100vh - 90px) 75 | @media ( max-width 1023px ) 76 | width 428px 77 | max-width 100% 78 | width 32% 79 | padding 0 0 0 1px 80 | overflow-y auto 81 | #loading 82 | font-family 'JetBrains Mono' 83 | display flex 84 | justify-content center 85 | div 86 | display inline-block 87 | p 88 | animation 2s loading infinite steps(4,jump-none) 89 | overflow-wrap normal 90 | overflow hidden 91 | display table-caption 92 | 93 | @keyframes loading 94 | 0% 95 | width calc(100% - 1.5em) 96 | 100% 97 | width 100% 98 | 99 | #search-result 100 | width 100% 101 | .recent-post 102 | font-family 'JetBrains Mono' 103 | margin 0 104 | padding 8px 105 | border none 106 | border-top 1px solid var(--theme-border-soft) 107 | border-bottom 1px solid var(--theme-border-soft) 108 | p 109 | margin .5em 110 | max-height 40px 111 | white-space initial 112 | overflow hidden 113 | b 114 | color var(--theme-text-light) 115 | &:hover .search-keyword 116 | color var(--theme-subcolor) 117 | transition .3s 118 | background-color unset 119 | overflow hidden 120 | .search-keyword 121 | background-color var(--theme-highlight) 122 | color var(--theme-text-light) 123 | .search-result-title 124 | font-size 1.1em 125 | #no-result p 126 | text-align center 127 | 128 | @media ( min-width 1024px ) 129 | .blur 130 | article, 131 | aside, 132 | #canvas-dust 133 | filter blur(0.8px) 134 | -------------------------------------------------------------------------------- /source/css/_modules/search/left.styl: -------------------------------------------------------------------------------- 1 | @media ( max-width 1023px ) 2 | .search .navItem:not(#search-header) 3 | transform translateX(-100%) 4 | pointer-events none 5 | 6 | @media ( min-width 769px ) and ( max-width 1023px ) 7 | .up 8 | #search-header 9 | left calc(100vw - 238px) 10 | .search-popup 11 | left calc(100vw - 238px) 12 | right 0 13 | transform translateX(100%) 14 | &.open 15 | transform translateX(0) 16 | .navBtn 17 | left calc(238px + 1em) 18 | header 19 | clip-path polygon(0 0, 0 100%, 100vw 100%, 100vw 0) 20 | 21 | @media ( min-width 1024px ) 22 | nav.search, 23 | nav.search-moving 24 | overflow hidden 25 | .search .navItem:not(#search-header) 26 | transform translateX(100%) 27 | pointer-event none 28 | .search-popup 29 | right 0 30 | transform translateX(100%) 31 | &.open 32 | transform translateX(-6px) 33 | #search-header 34 | input 35 | padding 0 10px 0 0 36 | .navItemTitle 37 | right 10px 38 | &::before 39 | border-right 4px solid var(--theme-border-light) 40 | right 0 41 | &::after 42 | right 0 43 | -------------------------------------------------------------------------------- /source/css/_modules/search/right.styl: -------------------------------------------------------------------------------- 1 | .search .navItem:not(#search-header) 2 | transform translateX(-100%) 3 | pointer-events none 4 | .search-popup 5 | left 0 6 | transform translateX(-100%) 7 | &.open 8 | transform translateX(0) 9 | 10 | @media ( min-width 769px ) and ( max-width 1023px ) 11 | .up :is(#search-header, .search-popup) 12 | left calc(100vw - 238px) 13 | :is(.up, .moving) header 14 | clip-path polygon(0 0, 0 100%, calc(100vw - 238px) 100%, calc(100vw - 238px) 0) 15 | 16 | @media ( min-width 1024px ) 17 | #search-header 18 | input 19 | padding 0 0 0 10px 20 | &::placeholder 21 | text-align right 22 | .navItemTitle::before 23 | border-left 4px solid var(--theme-border-light) 24 | left 0 25 | -------------------------------------------------------------------------------- /source/css/_modules/search/single_page.styl: -------------------------------------------------------------------------------- 1 | @media ( max-width 1023px ) 2 | .moving 3 | pointer-events none 4 | .navBtn 5 | pointer-events none 6 | .search-header, 7 | .search-popup 8 | transition unset 9 | pointer-events none 10 | .navContent 11 | overflow visible 12 | 13 | .up 14 | .search-popup 15 | left 100vw 16 | article 17 | margin-top 50px 18 | .closed 19 | .navBtn 20 | transform translateY(-.5em) 21 | .navContent 22 | overflow visible 23 | #search-header 24 | padding .5em 2em 0 5em 25 | animation get-in-top .3s 26 | position absolute 27 | input 28 | animation none 29 | .search-popup 30 | top 55px 31 | height calc(100vh - 55px) 32 | background-color var(--theme-bg-trans0) 33 | transform translateX(100%) 34 | 35 | #search-header 36 | transition unset 37 | top 0 38 | width 100% 39 | box-sizing border-box 40 | .navItemTitle 41 | border-color var(--theme-border-light) 42 | 43 | .down.moving header:not(.expanded) #search-header 44 | animation get-out-top .3s 45 | 46 | .search-popup 47 | left 0 48 | right 0 49 | transform translateX(-100%) 50 | &.open 51 | transform translateX(0) 52 | 53 | @media ( max-width 768px ) 54 | .up header:not(.expanded) #search-header 55 | left 100vw 56 | .up article 57 | margin-top 60px 58 | 59 | animate-up(distance) 60 | @keyframes get-out-top 61 | 0% 62 | padding .5em 2em 0 5em 63 | left distance 64 | transform translate(0, 0) 65 | position absolute 66 | 100% 67 | padding .5em 2em 0 5em 68 | left distance 69 | position absolute 70 | transform translate(0, -100%) 71 | 72 | @media ( min-width 769px ) 73 | animate-up(calc(100vw - 238px)) 74 | 75 | @media ( max-width 768px ) 76 | animate-up(100vw) 77 | 78 | @keyframes get-in-top 79 | 0% 80 | padding .5em 2em 0 5em 81 | transform translate(0, -100%) 82 | 100% 83 | padding .5em 2em 0 5em 84 | transform translate(0, 0) 85 | 86 | -------------------------------------------------------------------------------- /source/css/_modules/social.styl: -------------------------------------------------------------------------------- 1 | #social-links 2 | margin-top .5em 3 | display flex 4 | justify-content center 5 | flex-wrap wrap 6 | 7 | .social 8 | padding 0 3px 9 | display inline-block 10 | height 1.2em 11 | font-size 1.2em 12 | 13 | .social.img 14 | padding 0 15 | img 16 | height 1.2em 17 | -------------------------------------------------------------------------------- /source/css/_page/archive.styl: -------------------------------------------------------------------------------- 1 | #archive-flex 2 | width 100% 3 | height fit-content 4 | min-height 600px 5 | box-sizing border-box 6 | display flex 7 | justify-content stretch 8 | position: relative 9 | 10 | #archive-aside 11 | &::-webkit-scrollbar 12 | display none 13 | &::-ms-scrollbar 14 | display none 15 | scrollbar-width none 16 | padding-bottom 30px 17 | overflow auto 18 | box-sizing border-box 19 | padding-top 10px 20 | top 0 21 | height fit-content 22 | @media ( min-width 769px ) 23 | max-height 100vh 24 | display flex 25 | flex-grow 1 26 | flex-direction column 27 | 28 | #Archives, #Categories, #Tags 29 | margin 0 10px 30 | background-color var(--theme-bg-trans1) 31 | overflow-y auto 32 | &, h1 33 | transition .3s 34 | h1 35 | margin 0 36 | padding 0 15px 37 | color var(--theme-text-rev) 38 | background-color var(--theme-bg-light) 39 | font-size medium 40 | font-family BenderLight 41 | @media ( min-width 769px ) 42 | &:hover, &:target 43 | background-color var(--theme-bg-trans2) 44 | h1 45 | background-color var(--theme-highlight) 46 | 47 | #Archives 48 | margin-bottom 30px 49 | margin-top 10px 50 | @media ( min-width 769px ) 51 | min-height calc(100vh - 40px) 52 | flex-grow 5 53 | position relative 54 | h2 55 | margin 10px 0 56 | font-size large 57 | &:before 58 | content '' 59 | display inline-block 60 | width 5px 61 | height 15px 62 | margin-right 5px 63 | background-color var(--theme-subcolor) 64 | time 65 | color var(--theme-text-light) 66 | .categories, .tags 67 | display inline-block 68 | #Archives-bg 69 | box-sizing border-box 70 | padding 10px 71 | padding-bottom 30px 72 | 73 | .article-item 74 | padding-inline 20px 75 | display flex 76 | position relative 77 | margin-bottom 15px 78 | &::after 79 | content '' 80 | width calc(100% - 30px) 81 | position absolute 82 | display block 83 | bottom -5px 84 | left 15px 85 | border-bottom: 1px var(--theme-unimportant-trans) solid 86 | 87 | #Categories 88 | height fit-content 89 | overflow visible 90 | height 50% 91 | flex-grow 1 92 | margin-bottom 20px 93 | p 94 | text-align center 95 | 96 | #Tags 97 | height fit-content 98 | overflow visible 99 | height 100% 100 | flex-grow 1 101 | p 102 | text-align center 103 | 104 | #navigation a 105 | width 100% 106 | display inline-block 107 | padding 6px 0 108 | font-size x-large 109 | font-weight 900 110 | font-family BenderLight 111 | text-align center 112 | 113 | .control-archive 114 | width 55px 115 | display inline-block 116 | & + a 117 | width calc(100% - 55px) 118 | -------------------------------------------------------------------------------- /source/css/_page/article.styl: -------------------------------------------------------------------------------- 1 | article 2 | transition margin .3s 3 | box-sizing border-box 4 | position relative 5 | min-height calc(100vh - 10px) 6 | height fit-content 7 | min-width 1px 8 | #post-content p, .recent-excerpt p 9 | line-height 150% 10 | 11 | .posts 12 | margin-top 10px 13 | padding-bottom 72px 14 | width 100% 15 | min-height calc(100vh - 82px) 16 | 17 | .recent-post 18 | background-color var(--theme-bg-trans1) 19 | color var(--theme-unimportant) 20 | display block 21 | margin-bottom -1px 22 | border 1px solid var(--theme-unimportant) 23 | padding 13px 15px 24 | transition .3s 25 | .recent-info::after 26 | transition .3s 27 | .categories, .tags 28 | font-family BenderLight, sans-serif 29 | .categories 30 | color var(--theme-highlight) 31 | font-size large 32 | font-weight bold 33 | padding 0 10px 0 0 34 | .tags 35 | font-size small 36 | span 37 | display inline-block 38 | padding 0 5px 0 0 39 | time 40 | color var(--theme-unimportant) 41 | display inline-block 42 | text-align left 43 | float right 44 | hr 45 | color var(--theme-unimportant) 46 | border-color var(--theme-unimportant) 47 | img 48 | width 100% 49 | h1 50 | font-family sans-serif 51 | color var(--theme-text-light) 52 | margin 0 53 | padding 15px 0 0 0 54 | @media ( min-width 769px ) 55 | &:hover 56 | color var(--theme-text-hover) 57 | background-color var(--theme-highlight) 58 | time, .categories 59 | color var(--theme-text-hover) 60 | a, a:active 61 | color var(--theme-text-rev) 62 | .recent-info::after 63 | background-color var(--theme-bg-hover) 64 | .recent-excerpt a, a:hover 65 | color var(--theme-text-light) 66 | hr 67 | color var(--theme-highlight) 68 | border-color var(--theme-highlight) 69 | figure table 70 | .gutter 71 | background-color var(--theme-border) 72 | .code 73 | background-color var(--theme-bg-trans1) 74 | &, &:hover 75 | color var(--theme-text-light) 76 | blockquote 77 | &, &:hover 78 | color var(--theme-text-light) 79 | border-color var(--theme-border) 80 | background-color var(--theme-bg-trans1) 81 | .read-more 82 | color var(--theme-text-light) 83 | background-color var(--theme-bg-hover) 84 | .post-sticky 85 | color var(--theme-text-light) 86 | background-color var(--theme-bg-hover) 87 | transition .3s 88 | 89 | .recent-info 90 | min-height 25px 91 | &:after 92 | content '' 93 | width 13% 94 | display block 95 | height 5px 96 | background-color var(--theme-highlight) 97 | position relative 98 | bottom -6px 99 | 100 | .recent-excerpt 101 | margin 12px 0 28px 0 102 | 103 | .post-sticky 104 | background-color var(--theme-highlight) 105 | color var(--theme-text-rev) 106 | padding 1px 2px 107 | margin-right 5px 108 | transition .3s 109 | 110 | .read-more 111 | color var(--theme-background) 112 | display block 113 | float right 114 | font-size smaller 115 | font-weight 600 116 | background-color var(--theme-highlight) 117 | margin-top -21px 118 | padding 3px 10px 3px 40px 119 | font-family BenderLight 120 | 121 | #paginator 122 | width 100% 123 | user-select none 124 | margin 20px 0 125 | display flex 126 | flex-wrap wrap 127 | justify-content center 128 | position absolute 129 | bottom 0 130 | left 0 131 | a, span 132 | color var(--theme-text-light) 133 | font-weight bold 134 | margin 0 10px 0 0 135 | border 1px solid var(--theme-highlight) 136 | padding 5px 10px 137 | &:last-child 138 | margin 0 139 | @media ( min-width 769px ) 140 | a:hover 141 | color var(--theme-text-hover) 142 | background-color var(--theme-highlight) 143 | .current 144 | color var(--theme-text-hover) 145 | background-color var(--theme-highlight) 146 | -------------------------------------------------------------------------------- /source/css/_page/category.styl: -------------------------------------------------------------------------------- 1 | .category-list, .tag-list 2 | list-style none 3 | display block 4 | margin 0 5 | 6 | .category-list 7 | padding 0 8 | .category-list-item 9 | position relative 10 | @media ( min-width 769px ) 11 | &:hover 12 | a 13 | color var(--theme-highlight) 14 | border-left var(--theme-highlight) solid 5px 15 | background-color var(--theme-bg-soft-hover) 16 | span 17 | color var(--theme-text-light) 18 | .category-list-link 19 | width 100% 20 | padding 6px 40% 6px 10px 21 | display inline-block 22 | box-sizing border-box 23 | &:before, &:after 24 | color var(--theme-highlight) 25 | content '#' 26 | padding 0 5px 27 | .category-list-count 28 | padding 6px 10px 29 | position absolute 30 | right 0 31 | -------------------------------------------------------------------------------- /source/css/_page/page.styl: -------------------------------------------------------------------------------- 1 | @import 'archive' 2 | @import 'article' 3 | @import 'category' 4 | @import 'tag' 5 | @import 'post/*' 6 | -------------------------------------------------------------------------------- /source/css/_page/post/MathJax.styl: -------------------------------------------------------------------------------- 1 | .MathJax 2 | transform translateZ(0) 3 | .math.display 4 | display block 5 | width 100% 6 | overflow auto 7 | -------------------------------------------------------------------------------- /source/css/_page/post/bottom_btn.styl: -------------------------------------------------------------------------------- 1 | .bottom-btn 2 | position sticky 3 | bottom 0 4 | z-index 65536 5 | display flex 6 | flex-direction column 7 | align-items flex-end 8 | @media ( max-width 768px ) 9 | position fixed 10 | left 0 11 | width 100vw 12 | div 13 | position absolute 14 | right 8px 15 | bottom 8px 16 | a 17 | overflow hidden 18 | display block 19 | right 0 20 | width 40px 21 | height 40px 22 | color var(--theme-text-light) 23 | line-height 40px 24 | text-align center 25 | font-size 40px 26 | font-weight 900 27 | padding 0 28 | user-select none 29 | @media ( min-width 769px ) 30 | &:hover 31 | background-color var(--theme-subcolor) 32 | color var(--theme-text-hover) 33 | @media ( min-width 769px ) 34 | .i-top:hover 35 | line-height 30px 36 | .i-color 37 | display flex 38 | @media ( min-width 769px ) 39 | &:hover 40 | line-height 40px 41 | &::after 42 | transform rotate(90deg) 43 | &::after 44 | margin auto 45 | content '' 46 | height 16px 47 | width 16px 48 | display inline-block 49 | border 4px solid var(--theme-bg-light) 50 | border-radius 50% 51 | background linear-gradient(45deg, transparent 10px, 52 | var(--theme-bg-light) 12px, var(--theme-bg-light)) 53 | transition transform .3s, filter .3s 54 | -------------------------------------------------------------------------------- /source/css/_page/post/code.styl: -------------------------------------------------------------------------------- 1 | .gutter pre 2 | margin 6px 0 3 | padding-top 5px 4 | .code pre 5 | margin 6px 0 6 | .hljs span 7 | line-height 0 8 | 9 | .highlight 10 | line-height 20px 11 | margin 1em 12 | overflow-x hidden 13 | border unset 14 | table 15 | display block 16 | overflow auto 17 | .code-title 18 | color var(--theme-text-light) 19 | flex-grow 1 20 | .highlight > .ex-content 21 | padding-left 0 22 | background unset 23 | &:hover 24 | background unset 25 | .ex-header:not(:focus-visible)~.ex-content:not(:hover) > .code-copy:not(.copied,:focus-visible) 26 | opacity 0 27 | 28 | .code-copy 29 | position absolute 30 | top .5em 31 | right .5em 32 | height 25px 33 | width 25px 34 | border 1px solid var(--theme-border-light) 35 | color var(--theme-text-light) 36 | border-radius 2px 37 | transition .3s 38 | &::before 39 | content '' 40 | position absolute 41 | top 2px 42 | right 2px 43 | height 9px 44 | width 9px 45 | border 2px solid 46 | border-radius 2px 47 | &::after 48 | content '' 49 | position absolute 50 | bottom 2px 51 | left 2px 52 | height 9px 53 | width 9px 54 | border 2px solid 55 | border-radius 2px 56 | clip-path polygon(0 0,4px 0,4px 9px,100% 9px,100% 100%,0 100%) 57 | @media (min-width 769px) 58 | &:hover:not(.copied) 59 | color var(--theme-text-hover) 60 | border-color var(--theme-subcolor) 61 | background var(--theme-subcolor) 62 | @media (max-width 768px) 63 | &:active 64 | color var(--theme-subcolor) 65 | &.copied 66 | border-color var(--theme-subcolor) 67 | color var(--theme-subcolor) 68 | 69 | table 70 | td 71 | border 0 72 | code 73 | padding 0 8px 5px 8px 74 | background-color transparent!important 75 | .gutter 76 | position sticky 77 | color var(--theme-text-rev) 78 | text-align right 79 | background-color var(--theme-highlight) 80 | left 0 81 | padding 0 8px 5px 8px 82 | &, pre, span 83 | user-select none 84 | pointer-events none 85 | .code 86 | width 100% 87 | background-color var(--theme-bg-soft) 88 | transition .3s 89 | @media (min-width 769px) 90 | &:hover 91 | background-color var(--theme-bg-soft-hover) 92 | -------------------------------------------------------------------------------- /source/css/_page/post/post.styl: -------------------------------------------------------------------------------- 1 | #post-content 2 | h1, h2, h3, h4 ,h5, h6 3 | border-bottom var(--theme-unimportant-trans) solid 1px 4 | display flex 5 | h1 6 | font-size 1.75em 7 | h2 8 | font-size 1.60em 9 | h3 10 | font-size 1.45em 11 | h4 12 | font-size 1.30em 13 | h5 14 | font-size 1.15em 15 | h6 16 | font-size 1em 17 | 18 | 19 | #post-bg 20 | margin-top 10px 21 | width 100% 22 | box-sizing border-box 23 | padding 20px 30px 24 | background-color var(--theme-bg-trans1) 25 | overflow-x auto 26 | min-height calc(100vh - 20px) 27 | img 28 | max-width 100% 29 | 30 | #post-title 31 | flex-wrap wrap 32 | display flex 33 | flex-direction row 34 | justify-content space-between 35 | align-items center 36 | h1 37 | display inline-block 38 | font-size 2em 39 | hr 40 | color var(--theme-unimportant-2) 41 | position relative 42 | &:before 43 | content '' 44 | width 13% 45 | height 3px 46 | display block 47 | position absolute 48 | background-color var(--theme-text-light) 49 | top -3px 50 | left -1px 51 | #post-info 52 | text-align right 53 | time 54 | color var(--theme-highlight) 55 | .control 56 | text-align left 57 | display inline-block 58 | width 90px 59 | #post-source span 60 | color var(--theme-subcolor) 61 | background-color var(--theme-unimportant-2) 62 | 63 | #post-content 64 | padding-bottom 1em 65 | table 66 | width 100% 67 | .footnote-ref:before 68 | content '' 69 | display inline-block 70 | margin-top -60px 71 | width 1px 72 | height 60px 73 | visibility hidden 74 | .footnotes li:before 75 | content '' 76 | display block 77 | margin-top -60px 78 | height 60px 79 | visibility hidden 80 | .headerlink 81 | background-color var(--theme-highlight) 82 | margin 5px 7px 5px 0 83 | h1, h2 84 | &:target .headerlink 85 | background-color var(--theme-subcolor) 86 | .headerlink 87 | padding 0 0 0 6px 88 | h3, h4 ,h5 ,h6 89 | &:target .headerlink 90 | background-color var(--theme-subcolor) 91 | .headerlink 92 | padding 0 0 0 5px 93 | 94 | #reward 95 | margin 1em 0 96 | color var(--theme-text-rev) 97 | text-align center 98 | background-color var(--theme-bg-soft) 99 | &:hover 100 | background-color var(--theme-bg-soft-hover) 101 | summary 102 | background-color var(--theme-subcolor) 103 | div 104 | width 45% 105 | margin 0 106 | padding 20px 0 107 | display inline-block 108 | span 109 | color var(--theme-highlight) 110 | padding-right 10px 111 | img 112 | width 80% 113 | max-width 280px 114 | padding 0 20px 115 | 116 | #pages 117 | padding 5px 118 | display flex 119 | justify-content center 120 | border-top var(--theme-border) solid 2px 121 | 122 | .footer-link 123 | padding 5px 124 | width 50% 125 | align-self center 126 | height 100% 127 | position relative 128 | -------------------------------------------------------------------------------- /source/css/_page/tag.styl: -------------------------------------------------------------------------------- 1 | .tag-list 2 | padding 10px 3 | .tag-list-item 4 | position relative 5 | line-height 23px 6 | background-color var(--theme-tag-bg) 7 | display inline-block 8 | margin 5px 9 | border var(--theme-tag-border) solid 1px 10 | border-radius 3px 11 | &, a, span 12 | transition .3s 13 | @media ( min-width 769px ) 14 | &:hover 15 | border-color var(--theme-highlight) 16 | a 17 | color var(--theme-text-hover) 18 | background-color var(--theme-highlight) 19 | span 20 | background-color var(--theme-tag-bg) 21 | &:active 22 | border-color var(--theme-border) 23 | a 24 | background-color var(--theme-subcolor) 25 | .tag-list-link 26 | color var(--theme-text-light) 27 | padding 3px 6px 3px 12px 28 | display table-cell 29 | box-sizing border-box 30 | &::after 31 | content '' 32 | width 100% 33 | height 100% 34 | position absolute 35 | top 0 36 | left 0 37 | .tag-list-count 38 | width 10px 39 | padding 3px 6px 40 | color var(--theme-text-light) 41 | background-color var(--theme-tag-count-bg) 42 | display table-cell 43 | pointer-events none 44 | vertical-align middle 45 | -------------------------------------------------------------------------------- /source/css/arknights.styl: -------------------------------------------------------------------------------- 1 | // ===== 基础样式 2 | // == base style 3 | @import '_core/core' 4 | 5 | // ===== 组件相关 6 | // == modules 7 | @import '_modules/modules' 8 | 9 | // ===== 页面样式 10 | // == page style 11 | @import '_page/page' 12 | 13 | // ===== 自定义样式 14 | // == custom style 15 | @import '_custom/*' 16 | -------------------------------------------------------------------------------- /source/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/favicon.ico -------------------------------------------------------------------------------- /source/font/Bender.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/font/Bender.ttf -------------------------------------------------------------------------------- /source/font/BenderLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/font/BenderLight.woff2 -------------------------------------------------------------------------------- /source/font/Geometos.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/font/Geometos.woff2 -------------------------------------------------------------------------------- /source/font/JetBrainsMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/font/JetBrainsMono-Regular.woff2 -------------------------------------------------------------------------------- /source/icons/sound.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /source/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/bg.jpg -------------------------------------------------------------------------------- /source/img/bk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/bk.jpg -------------------------------------------------------------------------------- /source/img/faction/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/faction/1.png -------------------------------------------------------------------------------- /source/img/faction/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/faction/2.png -------------------------------------------------------------------------------- /source/img/faction/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/faction/3.png -------------------------------------------------------------------------------- /source/img/faction/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/faction/4.png -------------------------------------------------------------------------------- /source/img/faction/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/faction/5.png -------------------------------------------------------------------------------- /source/img/pc-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/img/pc-bg.jpg -------------------------------------------------------------------------------- /source/js/_src/include/BgmControl.ts: -------------------------------------------------------------------------------- 1 | function BgmControl() { 2 | const bgm = document.getElementById('bgm') as HTMLAudioElement; 3 | const control = document.getElementById("bgm-control"); 4 | if (bgm.paused) { 5 | bgm.play(); 6 | control!.setAttribute("fill", "#18d1ff"); 7 | control!.style.transform = "scaleY(1)"; 8 | } else { 9 | bgm.pause(); 10 | control!.setAttribute("fill", "currentColor"); 11 | control!.style.transform = "scaleY(.5)"; 12 | } 13 | } -------------------------------------------------------------------------------- /source/js/_src/include/Code.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict' 5 | 6 | class Code { 7 | private mermaids: string[] = [] 8 | 9 | private doAsMermaid = (item: Element) => { 10 | let Amermaid = item.querySelector('.mermaid') as HTMLElement 11 | item.outerHTML = '
    ' + Amermaid.innerText + '
    ' 12 | } 13 | 14 | private resetName = (str: string): string => { 15 | if (str == 'plaintext') { 16 | return 'TEXT' 17 | } 18 | if (str == 'cs') { 19 | return 'C#' 20 | } 21 | if (str == 'cpp') { 22 | return 'C++' 23 | } 24 | return str.toUpperCase() 25 | } 26 | 27 | private doAsCode = (item: Element) => { 28 | const code_fold = page_config.code_fold || config.code_fold || -1; 29 | const codeType = this.resetName(item.classList[1]), 30 | lineCount = getElement('.gutter', item).children[0].childElementCount >> 1 31 | item.classList.add(lineCount <= code_fold || code_fold === -1 ? 'open' : 'fold') 32 | item.classList.add('expand-box') 33 | item.innerHTML = 34 | `
    35 | 36 | ${format(config.code.codeInfo, codeType, lineCount)} 37 |
    38 |
    ${item.innerHTML} 39 | 40 |
    ` 41 | getElement('.code-copy', item).addEventListener('click', (click: Event) => { 42 | const button = click.target as HTMLElement 43 | navigator.clipboard.writeText(getElement('code', item).innerText) 44 | button.classList.add('copied') 45 | setTimeout(() => { 46 | button.classList.remove('copied') 47 | }, 1200) 48 | }) 49 | } 50 | 51 | public paintMermaid = () => { 52 | if (typeof (mermaid) === 'undefined') return; 53 | mermaid.initialize(document.documentElement.getAttribute('theme-mode') === 'dark' ? 54 | { theme: 'dark' } : { theme: 'default' }) 55 | if (typeof(mermaid.run) !== 'undefined') { 56 | mermaid.run({ querySelector: '.mermaid' }) 57 | } else { 58 | mermaid.init() 59 | } 60 | } 61 | 62 | public findCode = () => { 63 | let codeBlocks = document.querySelectorAll('.highlight') 64 | if (codeBlocks !== null) { 65 | codeBlocks.forEach(item => { 66 | if (item.getAttribute('code-find') === null) { 67 | try { 68 | if (!item.classList.contains('mermaid') && item.querySelector('.code-header') === null) { 69 | if (item.querySelector('.mermaid') !== null) { 70 | this.doAsMermaid(item) 71 | } else { 72 | this.doAsCode(item) 73 | } 74 | } 75 | } catch (e) { 76 | return 77 | } 78 | item.setAttribute('code-find', '') 79 | } 80 | }) 81 | } 82 | document.querySelectorAll('.mermaid').forEach((item) => { 83 | this.mermaids.push(item.outerHTML) 84 | }) 85 | expand.setHTML() 86 | } 87 | 88 | public resetMermaid = () => { 89 | if (typeof (mermaid) === 'undefined') return; 90 | let id = 0 91 | document.querySelectorAll('.mermaid').forEach((item) => { 92 | item.outerHTML = this.mermaids[id] 93 | ++id 94 | }) 95 | this.paintMermaid() 96 | } 97 | 98 | constructor() { 99 | this.findCode() 100 | document.addEventListener('pjax:success', this.findCode) 101 | window.addEventListener('hexo-blog-decrypt', this.findCode) 102 | } 103 | } 104 | 105 | let code = new Code() 106 | -------------------------------------------------------------------------------- /source/js/_src/include/ColorMode.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict' 5 | 6 | class ColorMode { 7 | private html: HTMLElement = document.documentElement 8 | private dark: boolean = this.html.getAttribute('theme-mode') === 'dark' 9 | private inChanging: boolean = false 10 | private btn: HTMLElement = getElement('#color-mode') 11 | 12 | public change = () => { 13 | this.inChanging = true 14 | let background = document.createElement('div') 15 | background.style.transition = '1.5s' 16 | background.innerHTML = 17 | `
    ` 24 | document.body.insertBefore(background, document.body.firstChild) 25 | this.btn.style.pointerEvents = 'none' 26 | setTimeout(() => { 27 | if (canvasDusts) canvasDusts.stop() 28 | if (this.dark) { 29 | this.html.setAttribute('theme-mode', 'light') 30 | this.dark = false 31 | window.localStorage['theme-mode'] = 'light' 32 | } else { 33 | this.html.setAttribute('theme-mode', 'dark') 34 | this.dark = true 35 | window.localStorage['theme-mode'] = 'dark' 36 | } 37 | background.style.opacity = '0' 38 | code.resetMermaid() 39 | }) 40 | setTimeout(() => { 41 | document.body.removeChild(background) 42 | if (canvasDusts) canvasDusts.play() 43 | }, 1500) 44 | setTimeout(() => { 45 | this.btn.style.pointerEvents = '' 46 | this.inChanging = false 47 | }, 1000) 48 | } 49 | 50 | constructor() { 51 | document.addEventListener('keypress', (ev: KeyboardEvent) => { 52 | if (this.inChanging) { 53 | return 54 | } 55 | if (ev.key === 'c' && ev.target && 56 | !['INPUT', 'TEXTAREA'].includes((ev.target as HTMLElement).tagName)) { 57 | this.change() 58 | } 59 | }) 60 | } 61 | } 62 | 63 | try { 64 | var colorMode = new ColorMode() 65 | } catch (e) {} 66 | -------------------------------------------------------------------------------- /source/js/_src/include/Comments.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict' 5 | 6 | class Comments { 7 | private search: string[] = ["valine", "gitalk", "waline", "artalk"] 8 | private elements: Pair[] = [] 9 | 10 | private setHTML = () => { 11 | if (!document.querySelector('#comments .selector')) return 12 | this.elements = [] 13 | this.search.forEach((item) => { 14 | try { 15 | this.elements.push(new Pair(getElement(`#${item}`), getElement(`.${item}-sel`))) 16 | } catch (e) {} 17 | }) 18 | new Selectors(this.elements, 0) 19 | } 20 | 21 | constructor() { 22 | this.setHTML() 23 | document.addEventListener('pjax:complete', this.setHTML) 24 | } 25 | } 26 | 27 | new Comments() 28 | -------------------------------------------------------------------------------- /source/js/_src/include/Cursors.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class Cursor { 6 | private now: MouseEvent = new MouseEvent('') 7 | private first: boolean = true 8 | private last: number = 0 9 | private moveIng: boolean = false 10 | private fadeIng: boolean = false 11 | private nowX: number = 0 12 | private nowY: number = 0 13 | private readonly outer: CSSStyleDeclaration 14 | private readonly effecter: CSSStyleDeclaration 15 | private readonly attention: string = 16 | `a,input,button,textarea, 17 | .navBtnIcon, 18 | #post-content img, 19 | .ex-header, 20 | .gt-user-inner, 21 | .wl-sort>li, 22 | #valine .vicon,#valine .vat, 23 | .lg-container img,.clickable` 24 | 25 | private set = (X: number = this.nowX, Y: number = this.nowY) => { 26 | this.outer.transform = 27 | `translate(calc(${X.toFixed(2)}px - 50%), 28 | calc(${Y.toFixed(2)}px - 50%))` 29 | } 30 | 31 | private move = (timestamp: number) => { 32 | if (this.now !== undefined) { 33 | let delX = this.now.x - this.nowX, 34 | delY = this.now.y - this.nowY 35 | this.nowX += delX * Math.min(0.025 * (timestamp - this.last), 1) 36 | this.nowY += delY * Math.min(0.025 * (timestamp - this.last), 1) 37 | this.set() 38 | this.last = timestamp 39 | if (Math.abs(delX) > 0.1 || Math.abs(delY) > 0.1) { 40 | window.requestAnimationFrame(this.move) 41 | } else { 42 | this.set(this.now.x, this.now.y) 43 | this.moveIng = false 44 | } 45 | } 46 | } 47 | 48 | private reset = (mouse: MouseEvent) => { 49 | this.outer.top = '0' 50 | this.outer.left = '0' 51 | if (!this.moveIng) { 52 | this.moveIng = true 53 | window.requestAnimationFrame(this.move) 54 | } 55 | this.now = mouse 56 | if (this.first) { 57 | this.first = false 58 | this.nowX = this.now.x 59 | this.nowY = this.now.y 60 | this.set() 61 | } 62 | } 63 | 64 | private Aeffect = (mouse: MouseEvent) => { 65 | if (this.fadeIng == false) { 66 | this.fadeIng = true 67 | this.effecter.left = String(mouse.x) + 'px' 68 | this.effecter.top = String(mouse.y) + 'px' 69 | this.effecter.transition = 70 | 'transform .5s cubic-bezier(0.22, 0.61, 0.21, 1)\ 71 | ,opacity .5s cubic-bezier(0.22, 0.61, 0.21, 1)' 72 | this.effecter.transform = 'translate(-50%, -50%) scale(1)' 73 | this.effecter.opacity = '0' 74 | setTimeout(() => { 75 | this.fadeIng = false 76 | this.effecter.transition = '' 77 | this.effecter.transform = 'translate(-50%, -50%) scale(0)' 78 | this.effecter.opacity = '1' 79 | }, 500) 80 | } 81 | } 82 | 83 | private hold = () => { 84 | this.outer.height = '24px' 85 | this.outer.width = '24px' 86 | this.outer.background = "var(--theme-cursor-bg)" 87 | } 88 | 89 | public relax = () => { 90 | this.outer.height = '36px' 91 | this.outer.width = '36px' 92 | this.outer.background = "unset" 93 | } 94 | 95 | private pushHolder = () => { 96 | document.querySelectorAll(this.attention).forEach(item => { 97 | if (!(item as HTMLElement).classList.contains('is--active')) { 98 | item.addEventListener('mouseover', this.hold, { passive: true }) 99 | item.addEventListener('mouseout', this.relax, { passive: true }) 100 | } 101 | }) 102 | } 103 | 104 | constructor() { 105 | let node: HTMLElement = document.createElement('div') 106 | node.id = 'cursor-container' 107 | node.innerHTML = `
    ` 108 | document.body.appendChild(node) 109 | this.outer = getElement('#cursor-outer', node).style 110 | this.outer.top = '-100%' 111 | this.effecter = getElement('#cursor-effect', node).style 112 | this.effecter.transform = 'translate(-50%, -50%) scale(0)' 113 | this.effecter.opacity = '1' 114 | window.addEventListener('mousemove', this.reset, { passive: true }) 115 | window.addEventListener('click', this.Aeffect, { passive: true }) 116 | this.pushHolder() 117 | const observer = new MutationObserver(this.pushHolder) 118 | observer.observe(document, { childList: true, subtree: true }) 119 | } 120 | } 121 | new Cursor(); 122 | -------------------------------------------------------------------------------- /source/js/_src/include/Expands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | class expands { 4 | private reverse = (item: Element, s0: string, s1: string) => { 5 | const block = getParent(item) 6 | if (block.classList.contains(s0)) { 7 | block.classList.remove(s0) 8 | block.classList.add(s1) 9 | } else { 10 | block.classList.remove(s1) 11 | block.classList.add(s0) 12 | } 13 | } 14 | 15 | private addEvent = (header: HTMLElement) => { 16 | header.addEventListener('click', (click) => { 17 | if ((click.target as HTMLElement).tagName !== 'BUTTON' && 18 | (click.target as HTMLElement).tagName !== 'A') { 19 | this.reverse(header, 'open', 'fold') 20 | } 21 | }) 22 | header.addEventListener('keypress', (key) => { 23 | if (key.key === 'Enter') { 24 | this.reverse(header, 'open', 'fold') 25 | } 26 | }) 27 | } 28 | 29 | public setHTML = () => { 30 | document.querySelectorAll('.expand-box').forEach((item) => { 31 | this.addEvent(item.children[0] as HTMLElement) 32 | }) 33 | } 34 | constructor() {} 35 | } 36 | 37 | let expand = new expands(); 38 | -------------------------------------------------------------------------------- /source/js/_src/include/Header.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class Header { 6 | private readonly header: HTMLElement = getElement('header') 7 | private readonly button: HTMLElement = getElement('.navBtnIcon') 8 | private closeSearch: boolean = false 9 | private readyRev: boolean = true 10 | 11 | private relabel = () => { 12 | let navs = this.header.querySelectorAll('.navItem'), 13 | mayLen = 0, may = navs.item(0) 14 | navs.forEach(item => { 15 | try { 16 | let now = item as HTMLElement, 17 | link = getElement('a', now) as HTMLAnchorElement 18 | if (link !== null) { 19 | let href = link.href, match = now.getAttribute('matchdata') 20 | now.classList.remove('active') 21 | if (getParent(link) != now) { 22 | return 23 | } 24 | if (href.length > mayLen && document.URL.match(href) !== null) { 25 | mayLen = href.length 26 | may = now 27 | } 28 | if (match) { 29 | const s = match.split(',') 30 | s.forEach(item => { 31 | if (document.URL.match(item) !== null) { 32 | may = now 33 | mayLen = Infinity 34 | } 35 | }) 36 | } 37 | } 38 | } catch (e) {} 39 | }) 40 | if (may !== null) { 41 | do { 42 | if (may.classList.contains('navItem')) { 43 | may.classList.add('active') 44 | } 45 | } while (!(may = getParent(may)).classList.contains('navContent')) 46 | } 47 | } 48 | 49 | public inHeader = (mouse: MouseEvent) => { 50 | let range = this.header.getBoundingClientRect() 51 | if (mouse.clientX < range.x || mouse.clientY < range.y || 52 | mouse.clientX > range.right || mouse.clientY > range.bottom){ 53 | this.close() 54 | } 55 | } 56 | 57 | public open = (item: Element = this.header) => { 58 | item.classList.add('expanded') 59 | item.classList.remove('closed') 60 | scrolls.slideDown() 61 | if (item === this.header) { 62 | item.classList.add('moving') 63 | setTimeout(() => item.classList.remove('moving'), 300) 64 | } 65 | document.addEventListener('click', this.inHeader) 66 | } 67 | 68 | public close = (item: Element = this.header) => { 69 | document.removeEventListener('click', this.inHeader) 70 | item.classList.add('closed') 71 | item.classList.remove('expanded') 72 | if (item === this.header) { 73 | item.classList.add('moving') 74 | setTimeout(() => item.classList.remove('moving'), 300) 75 | this.closeAll() 76 | getElement('nav', item).classList.remove('moved'); 77 | } 78 | } 79 | 80 | public reverse = (item: Element = this.header) => { 81 | if (this.closeSearch) { 82 | this.closeSearch = false 83 | return 84 | } 85 | if (!this.readyRev) { 86 | return 87 | } 88 | this.readyRev = false 89 | if (item.classList.contains('expanded')) { 90 | this.close(item) 91 | } else { 92 | this.open(item) 93 | } 94 | setTimeout(() => this.readyRev = true, 300) 95 | } 96 | 97 | public closeAll = () => { 98 | this.header.querySelectorAll('.expanded').forEach((item) => 99 | item.classList.remove('expanded')) 100 | } 101 | 102 | constructor() { 103 | this.relabel() 104 | document.addEventListener('pjax:success', this.relabel) 105 | document.addEventListener('pjax:send', () => this.close()) 106 | this.button.addEventListener('mousedown', () => { 107 | if (document.querySelector('.search')) { 108 | this.closeSearch = true 109 | } 110 | }) 111 | this.button.onclick = () => this.reverse(this.header) 112 | document.querySelectorAll('.navItemList').forEach((item) => { 113 | item = getParent(item) 114 | item.addEventListener('click', (event) => { 115 | if (getParent(event.target as Element) === item) { 116 | this.reverse(item) 117 | } 118 | }) 119 | }) 120 | } 121 | } 122 | 123 | var header = new Header() 124 | -------------------------------------------------------------------------------- /source/js/_src/include/Index.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class Index { 6 | private lastIndex: number = -1 7 | private headerLink: NodeList = document.querySelectorAll('null') 8 | private tocLink: NodeList = document.querySelectorAll('null') 9 | 10 | private setItem = (item: HTMLElement) => { 11 | item.classList.add('active') 12 | let parent = getParent(item), brother = parent.children 13 | for (let i = 0, length = brother.length; i < length; ++i) { 14 | const item = brother.item(i) as HTMLElement 15 | if (item.classList.contains('toc-child')) { 16 | item.classList.add('has-active') 17 | break 18 | } 19 | } 20 | for (; parent.classList[0] !== 'toc'; parent = getParent(parent)) { 21 | if (parent.classList[0] === 'toc-child') { 22 | parent.classList.add('has-active') 23 | } 24 | } 25 | } 26 | 27 | private reset = (not: HTMLElement) => { 28 | let tocs: NodeList = document.querySelectorAll('#toc-div .active') 29 | let tocTree: NodeList = document.querySelectorAll('#toc-div .has-active') 30 | tocs.forEach(item => { 31 | if (!item.contains(not)) { 32 | (item as HTMLElement).classList.remove('active') 33 | } 34 | }) 35 | tocTree.forEach(item => { 36 | if (!(item.parentElement as HTMLElement).contains(not)) { 37 | (item as HTMLElement).classList.remove('has-active') 38 | } 39 | }) 40 | } 41 | 42 | private check = (index: Array, id: number) => { 43 | return index[id + 1] > window.innerHeight / 3 || index[id] > 0 44 | } 45 | 46 | private modifyIndex = () => { 47 | let index: Array = [] 48 | this.headerLink.forEach(item => { 49 | index.push((item as HTMLElement).getBoundingClientRect().top) 50 | }) 51 | if (this.lastIndex >= 0 && 52 | (this.lastIndex < 1 || !this.check(index, this.lastIndex - 1)) && 53 | this.check(index, this.lastIndex)) { 54 | return 55 | } 56 | for (let i = 0; i < this.tocLink.length; ++i) { 57 | const item = this.tocLink.item(i) as HTMLElement 58 | if (i + 1 === index.length || this.check(index, i)) { 59 | this.lastIndex = i 60 | this.setItem(item) 61 | this.reset(item) 62 | return 63 | } 64 | } 65 | this.lastIndex = 0 66 | this.setItem(this.tocLink.item(0) as HTMLElement) 67 | this.reset(this.tocLink.item(0) as HTMLElement) 68 | } 69 | 70 | private setHTML = () => { 71 | try { 72 | this.headerLink = getElement('#post-content').querySelectorAll('h1,h2,h3,h4,h5,h6') 73 | this.tocLink = document.querySelectorAll('.toc-link') 74 | if (this.tocLink.length) { 75 | this.setItem(this.tocLink.item(0) as HTMLElement) 76 | } 77 | } catch {} 78 | } 79 | 80 | constructor() { 81 | this.setHTML() 82 | document.addEventListener('pjax:success', this.setHTML) 83 | window.addEventListener('hexo-blog-decrypt', this.setHTML) 84 | getElement('main').addEventListener('scroll', () => { 85 | if (this.tocLink.length) { 86 | this.modifyIndex() 87 | } 88 | }, { passive: true }) 89 | } 90 | } 91 | 92 | let indexs = new Index() 93 | -------------------------------------------------------------------------------- /source/js/_src/include/Scroll.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class Scroll { 6 | private scrolling: number = 0 7 | private getingtop: boolean = false 8 | private height: number = 0 9 | private visible: boolean = false 10 | private touchX: number = 0 11 | private touchY: number = 0x7fffffff 12 | private notMoveY: boolean = false 13 | private reallyUp: boolean = false 14 | private intop: boolean = false 15 | private totop: HTMLElement 16 | 17 | public scrolltop = () => { 18 | getElement('main').scroll({ top: 0, left: 0, behavior: 'smooth' }) 19 | this.totop.style.opacity = '0' 20 | this.getingtop = true 21 | setTimeout(() => this.totop.style.display = 'none', 300) 22 | } 23 | 24 | private totopChange = (top: number) => { 25 | if (top < -200) { 26 | this.totop.style.display = '' 27 | this.visible = true 28 | setTimeout(() => { 29 | if (this.visible) { 30 | this.totop.style.opacity = '1' 31 | } 32 | }, 300) 33 | } else { 34 | this.totop.style.opacity = '0' 35 | this.visible = false 36 | setTimeout(() => { 37 | if (!this.visible) { 38 | this.totop.style.display = 'none' 39 | } 40 | }, 300) 41 | } 42 | } 43 | 44 | public slideDown = () => { 45 | if (!this.intop) { 46 | return 47 | } 48 | const main = getElement('main').classList 49 | if (!document.querySelector('.expanded')) { 50 | getElement('.navBtn').classList.add('hide-btn') 51 | } 52 | main.remove('up') 53 | main.add('down') 54 | main.add('down') 55 | main.add('moving') 56 | setTimeout(() => { 57 | main.remove('down') 58 | main.remove('moving') 59 | }, 300) 60 | this.intop = false 61 | } 62 | 63 | public slideUp = () => { 64 | if (this.intop || document.querySelector('.moving')) { 65 | return 66 | } 67 | if (!document.querySelector('#search-header')) { 68 | getElement('.navBtn').classList.remove('hide-btn') 69 | return 70 | } 71 | const main = getElement('main').classList 72 | getElement('.navBtn').classList.remove('hide-btn') 73 | main.remove('down') 74 | main.add('up') 75 | main.add('moving') 76 | this.intop = true 77 | setTimeout(() => getElement('main').classList.remove('moving'), 300) 78 | } 79 | 80 | private setHTML = () => { 81 | try { 82 | let navBtn: HTMLElement = getElement('.navBtn') 83 | let onScroll = () => { 84 | try { 85 | let nowheight: number = getElement('article').getBoundingClientRect().top 86 | if (nowheight > 0) { 87 | return 88 | } 89 | if (!document.querySelector('.expanded')) { 90 | if (this.height - nowheight > 100) { 91 | navBtn.classList.add('hide-btn') 92 | this.height = nowheight 93 | } else if (nowheight > this.height) { 94 | if (nowheight - this.height > 20) { 95 | navBtn.classList.remove('hide-btn') 96 | } 97 | this.height = nowheight 98 | } 99 | } 100 | ++this.scrolling 101 | setTimeout(() => { 102 | if (!--this.scrolling) { 103 | this.getingtop = false 104 | } 105 | }, 100) 106 | if (!this.getingtop) { 107 | this.totopChange(nowheight) 108 | } 109 | } catch (e) {} 110 | } 111 | getElement('main').addEventListener('scroll', onScroll) 112 | this.height = 0 113 | this.visible = false 114 | this.totop = getElement('#to-top') 115 | this.setListener() 116 | } catch (e) {} 117 | } 118 | 119 | private checkTouchMove = (event: TouchEvent) => { 120 | if (Math.abs(event.changedTouches[0].screenX - this.touchX) > 50 && 121 | !this.reallyUp) { 122 | this.notMoveY = true 123 | } 124 | if (document.querySelector('.expanded') || 125 | window.innerWidth > 1024 || 126 | this.notMoveY || 127 | event.changedTouches[0].screenY === this.touchY || 128 | document.querySelector('.moving')) { 129 | return 130 | } 131 | if (this.intop || getElement('article').getBoundingClientRect().top >= 0) { 132 | this.reallyUp = true 133 | if (event.changedTouches[0].screenY > this.touchY) { 134 | this.slideUp() 135 | } else { 136 | this.slideDown() 137 | } 138 | this.touchY = event.changedTouches[0].screenY 139 | } 140 | } 141 | 142 | private startTouch = (event: TouchEvent) => { 143 | this.touchX = event.changedTouches[0].screenX 144 | this.touchY = event.changedTouches[0].screenY 145 | this.notMoveY = false 146 | } 147 | 148 | private checkPos = () => { 149 | if(getElement('article').getBoundingClientRect().top < 0 && this.intop) { 150 | this.slideDown() 151 | } 152 | } 153 | 154 | /** 155 | * used for `supScroll` and `footNoteScroll` functions 156 | */ 157 | private setListener = () => { 158 | getElement('#post-content').addEventListener('click', this.supScroll) 159 | getElement('#footnotes').addEventListener('click', this.footNoteScroll) 160 | } 161 | 162 | private supScroll = (event: Event) => { 163 | const target = event.target as HTMLAnchorElement 164 | const targetParent = getParent(target) 165 | 166 | if (targetParent?.tagName === 'SUP') { 167 | event.preventDefault() 168 | const hash = target.href.split('/').pop()?.slice(1) || '' 169 | document.getElementById(hash)?.scrollIntoView({ behavior: 'smooth' }) 170 | return 171 | } 172 | } 173 | 174 | private footNoteScroll = (event: Event) => { 175 | const target = event.target as HTMLAnchorElement 176 | if (target.tagName === 'A') { 177 | event.preventDefault() 178 | const hash = target.href.split('/').pop()?.slice(1) || '' 179 | document.getElementById(hash)?.scrollIntoView({ behavior: 'smooth' }) 180 | } 181 | } 182 | 183 | constructor() { 184 | document.addEventListener('pjax:success', this.setHTML) 185 | document.addEventListener('touchstart', this.startTouch) 186 | document.addEventListener('touchmove', this.checkTouchMove) 187 | document.addEventListener('touchend', this.checkPos) 188 | document.addEventListener('wheel', (event: WheelEvent) => { 189 | if (document.querySelector('.expanded') || window.innerWidth > 1024) { 190 | return 191 | } 192 | if (getElement('article').getBoundingClientRect().top >= 0) { 193 | if (event.deltaY < 0) { 194 | this.slideUp() 195 | } else { 196 | this.slideDown() 197 | } 198 | } 199 | }) 200 | this.setHTML() 201 | this.totop = document.querySelector('#to-top') as HTMLElement 202 | } 203 | } 204 | 205 | var scrolls = new Scroll() 206 | -------------------------------------------------------------------------------- /source/js/_src/include/canvaDust.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class dust { 6 | public x: number 7 | public y: number 8 | public vx: number = Math.random() * 1 + 1 9 | public vy: number = Math.random() * 1 + 0.01 10 | public shadowBlur: number = Math.random() * 3 11 | public shadowX: number = (Math.random() * 2) - 1 12 | public shadowY: number = (Math.random() * 2) - 1 13 | public radiusX: number = Math.random() * 1.5 + 0.5 14 | public radiusY: number = this.radiusX * (Math.random() * (1.3 - 0.3) + 0.3) 15 | public rotation: number = Math.PI * Math.floor(Math.random() * 2) 16 | constructor(x: number = 50, y: number = 50) { 17 | this.x = x 18 | this.y = y 19 | } 20 | } 21 | 22 | class canvasDust { 23 | private readonly canvas: HTMLCanvasElement 24 | private readonly ctx: CanvasRenderingContext2D 25 | public color: string = '#fff' 26 | public width: number = 300 27 | public height: number = 300 28 | private dustQuantity: number = 50 29 | public dustArr: Array = [] 30 | private inStop: boolean = false 31 | 32 | constructor(canvasID: string) { 33 | const canvas: HTMLCanvasElement = getElement(canvasID) as HTMLCanvasElement 34 | this.canvas = canvas 35 | this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D 36 | this.build() 37 | window.addEventListener('resize', this.resize) 38 | } 39 | 40 | private build = () => { 41 | this.resize() 42 | if (this.ctx) { 43 | const point = canvasDust.getPoint(this.dustQuantity) 44 | for (let i of point) { 45 | const dustObj = new dust(i[0], i[1]) 46 | this.buildDust(dustObj) 47 | this.dustArr.push(dustObj) 48 | } 49 | requestAnimationFrame(this.paint) 50 | } 51 | } 52 | 53 | private paint = () => { 54 | if (this.inStop) { 55 | return 56 | } 57 | const dustArr = this.dustArr 58 | for (let i of dustArr) { 59 | this.ctx.clearRect(i.x - 6, i.y - 6, 12, 12) 60 | if (i.x < -5 || i.y < -5) { 61 | const x: number = this.width 62 | const y: number = Math.floor(Math.random() * window.innerHeight) 63 | i.x = x 64 | i.y = y 65 | } else { 66 | i.x -= i.vx 67 | i.y -= i.vy 68 | } 69 | } 70 | for (let i of dustArr) { 71 | this.buildDust(i) 72 | } 73 | requestAnimationFrame(this.paint) 74 | } 75 | 76 | private buildDust = (dust: dust) => { 77 | const ctx = this.ctx 78 | ctx.beginPath() 79 | ctx.shadowBlur = dust.shadowBlur 80 | ctx.shadowOffsetX = dust.shadowX 81 | ctx.shadowOffsetY = dust.shadowY 82 | ctx.ellipse(dust.x, dust.y, dust.radiusX, dust.radiusY, dust.rotation, 0, Math.PI * 2) 83 | ctx.closePath() 84 | ctx.fill() 85 | } 86 | 87 | private resize = () => { 88 | const canvas = this.canvas 89 | const width = window.innerWidth 90 | const height = window.innerHeight 91 | this.width = width 92 | this.height = height 93 | this.dustQuantity = Math.floor((width + height) / 38) 94 | canvas.width = width 95 | canvas.height = height 96 | this.ctx.shadowColor = 97 | this.ctx.fillStyle = this.color 98 | } 99 | 100 | private static getPoint = (number: number = 1): Array<[number, number]> => { 101 | let point: Array<[number, number]> = [] 102 | for (let i: number = 0; i < number; ++i) { 103 | const x: number = Math.floor(Math.random() * window.innerWidth) 104 | const y: number = Math.floor(Math.random() * window.innerHeight) 105 | point.push([x, y]) 106 | } 107 | return point 108 | } 109 | 110 | public stop = () => { 111 | this.inStop = true 112 | } 113 | public play = () => { 114 | if (this.inStop === true) { 115 | this.inStop = false 116 | requestAnimationFrame(this.paint) 117 | } 118 | } 119 | } 120 | 121 | try { 122 | var canvasDusts = new canvasDust('#canvas-dust') 123 | } catch (e) {} 124 | -------------------------------------------------------------------------------- /source/js/_src/include/common/base.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | function getElement(string: string, item: Element = document.documentElement): HTMLElement { 6 | let tmp: HTMLElement | null = item.querySelector(string) 7 | if (tmp === null) { 8 | throw new Error("Unknown HTML") 9 | } 10 | return tmp 11 | } 12 | 13 | function getParent(item: Element, level: number = 1): HTMLElement { 14 | while (level--) { 15 | let tmp: HTMLElement | null = item.parentElement 16 | if (tmp === null) { 17 | throw new Error("Unknown HTML") 18 | } 19 | item = tmp 20 | } 21 | return item as HTMLElement 22 | } 23 | 24 | function format(format: string, ...args: any[]): string { 25 | return format.replaceAll(/\$\*?[0-9]*/g, (match) => { 26 | if (match === '$*') { 27 | return '' 28 | } 29 | let Index = match.slice(1) as unknown as number; 30 | if (Index >= args.length) { 31 | return '' 32 | } 33 | return args[Index] 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /source/js/_src/include/common/enviroment.d.ts: -------------------------------------------------------------------------------- 1 | declare var config: { 2 | root: string 3 | code_fold: number 4 | search: { 5 | preload: string 6 | activeHolder: string 7 | blurHolder: string 8 | noResult: string 9 | } 10 | code: { 11 | copy: string 12 | codeInfo: string 13 | } 14 | } 15 | 16 | declare var page_config: { 17 | title: string 18 | path: string 19 | date: string 20 | updated: string 21 | code_fold: number | null 22 | } 23 | 24 | declare var mermaid: { 25 | run: Function 26 | init: Function 27 | initialize: Function 28 | } | undefined 29 | -------------------------------------------------------------------------------- /source/js/_src/include/common/selectors.ts: -------------------------------------------------------------------------------- 1 | class Pair { 2 | public comment: HTMLElement 3 | public button: HTMLElement 4 | constructor(first: HTMLElement, second: HTMLElement) { 5 | this.comment = first 6 | this.button = second 7 | } 8 | } 9 | 10 | class Selectors { 11 | private elements: Pair[] = [] 12 | private nowActive: Pair 13 | 14 | private changeTo = (item: Pair) => { 15 | if (item === this.nowActive) { 16 | return 17 | } 18 | this.nowActive.comment.style.display = 'none' 19 | this.nowActive.button.classList.remove('active') 20 | item.comment.style.display = '' 21 | item.button.classList.add('active') 22 | this.nowActive = item 23 | } 24 | 25 | constructor(elements: Pair[] = [], active: number = 0) { 26 | this.elements = elements 27 | this.nowActive = this.elements[active] 28 | this.elements.forEach((item) => item.comment.style.display = 'none') 29 | this.nowActive = this.elements[0] 30 | for (let i of this.elements) { 31 | i.button.addEventListener('click', () => this.changeTo(i)) 32 | } 33 | this.nowActive.comment.style.display = '' 34 | this.nowActive.button.classList.add('active') 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /source/js/_src/include/pjaxSupport.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 'use strict' 4 | 5 | class pjaxSupport { 6 | private readonly loading: HTMLElement = getElement('.loading') 7 | private readonly left: HTMLElement = getElement('.loadingBar.left') 8 | private readonly right: HTMLElement = getElement('.loadingBar.right') 9 | private timestamp: number = 0 10 | 11 | private start = (need: number) => { 12 | this.left.style.transform = `scaleX(${need})` 13 | this.right.style.transform = `scaleX(${need})` 14 | ++this.timestamp 15 | } 16 | 17 | private loaded = () => { 18 | getElement('main').scrollTop = 0 19 | this.start(1) 20 | setTimeout((time: number) => { 21 | if (this.timestamp === time) { 22 | this.loading.style.opacity = '0' 23 | } 24 | }, 600, this.timestamp) 25 | } 26 | 27 | private fail = () => { 28 | setTimeout((time: number) => { 29 | if (this.timestamp !== time) { 30 | return; 31 | } 32 | this.start(0) 33 | this.loading.classList.add('fail') 34 | setTimeout((time: number) => { 35 | if (this.timestamp === time) { 36 | this.loading.style.opacity = '0' 37 | this.loading.classList.remove('fail') 38 | } 39 | }, 600, this.timestamp) 40 | }, 600, this.timestamp) 41 | } 42 | 43 | constructor() { 44 | document.addEventListener('pjax:send', () => { 45 | if (getElement('main').classList.contains('up')) { 46 | scrolls.slideDown() 47 | } 48 | this.loading.classList.add('reset') 49 | this.loading.classList.remove('fail') 50 | this.start(0) 51 | setTimeout((time: number) => { 52 | if (this.timestamp !== time) { 53 | return; 54 | } 55 | this.loading.classList.remove('reset') 56 | this.start(0.3) 57 | this.loading.style.opacity = '1' 58 | setTimeout((time: number) => { 59 | if (this.timestamp === time) { 60 | this.start(0.6) 61 | } 62 | }, 1200, this.timestamp) 63 | }, 0, this.timestamp) 64 | }) 65 | document.addEventListener('pjax:start', this.loaded) 66 | document.addEventListener('pjax:error', this.fail) 67 | } 68 | } 69 | 70 | try { 71 | new pjaxSupport() 72 | } catch (e) {} 73 | -------------------------------------------------------------------------------- /source/js/_src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./include/**/*.ts"], 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "esModuleInterop": true, 6 | "strict": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "outFile": "../arknights.js", 9 | "moduleResolution": "node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /source/js/search.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | let fetched = false, fetching = false, waiting = false 3 | let datas 4 | const path = config.root + 'search.json' 5 | const input = getElement('#search-input') 6 | const nav = getElement('nav') 7 | const activeHolder = config.search.activeHolder 8 | const blurHolder = config.search.blurHolder 9 | const noResult = config.search.noResult 10 | const popup = getElement('.search-popup') 11 | function fetechData() { 12 | fetching = true 13 | fetch(path) 14 | .then(response => response.text()) 15 | .then(res => { 16 | fetched = true 17 | datas = JSON.parse(res) 18 | if (waiting === true) { 19 | inputEventFunction() 20 | } 21 | }).catch(() => fetching = false) 22 | } 23 | if (config.search.preload) { 24 | fetechData() 25 | } 26 | function getIndexByWord(word, text, caseSensitive) { 27 | let wordLen = word.length 28 | if (wordLen === 0) return [] 29 | let startPosition = 0 30 | let position = [] 31 | let index = [] 32 | if (!caseSensitive) { 33 | text = text.toLowerCase() 34 | word = word.toLowerCase() 35 | } 36 | while ((position = text.indexOf(word, startPosition)) > -1) { 37 | index.push({ 38 | position: position, 39 | word: word 40 | }) 41 | startPosition = position + wordLen 42 | } 43 | return index 44 | } 45 | function mergeIntoSlice(start, end, index, searchText) { 46 | let item = index[index.length - 1] 47 | let position = item.position 48 | let word = item.word 49 | let hits = [] 50 | let searchTextCountInSlice = 0 51 | while (position + word.length <= end && index.length !== 0) { 52 | if (word === searchText) { 53 | searchTextCountInSlice++ 54 | } 55 | hits.push({ 56 | position: position, 57 | length: word.length 58 | }) 59 | let wordEnd = position + word.length 60 | index.pop() 61 | while (index.length !== 0) { 62 | item = index[index.length - 1] 63 | position = item.position 64 | word = item.word 65 | if (wordEnd > position) { 66 | index.pop() 67 | } else { 68 | break 69 | } 70 | } 71 | } 72 | return { 73 | hits: hits, 74 | start: start, 75 | end: end, 76 | TextCount: searchTextCountInSlice 77 | } 78 | } 79 | function highlightKeyword(text, slice) { 80 | let result = '' 81 | let prevEnd = slice.start 82 | slice.hits.forEach(hit => { 83 | result += text.substring(prevEnd, hit.position) 84 | let end = hit.position + hit.length 85 | result += `${text.substring(hit.position, end)}` 86 | prevEnd = end 87 | }) 88 | result += text.substring(prevEnd, slice.end) 89 | return result 90 | } 91 | function inLoading() { 92 | getElement('#search-result').innerHTML = '

    Loading...

    ' 93 | } 94 | function onPopupClose() { 95 | if (document.querySelector('.up') && document.querySelector('.closed')) { 96 | getElement('.navBtn').classList.remove('expanded') 97 | } 98 | getElement('#search-result').querySelectorAll('a'). 99 | forEach((item) => item.setAttribute('tabindex', -1)) 100 | document.body.classList.remove('blur') 101 | popup.classList.remove('open') 102 | } 103 | function proceedSearch() { 104 | document.body.classList.add('blur') 105 | if (document.querySelector('.up') && document.querySelector('.closed')) { 106 | getElement('.navBtn').classList.add('expanded') 107 | } 108 | getElement('#search-result').removeAttribute('tabindex') 109 | popup.classList.add('open') 110 | if (fetched === true) { 111 | popup.innerHTML = "
    " 112 | document.getElementById('search-result').innerHTML = '' 113 | } else { 114 | inLoading() 115 | } 116 | } 117 | function inputEventFunction() { 118 | let searchText = input.value.trim().toLowerCase() 119 | if (!searchText.length) { 120 | input.placeholder = activeHolder 121 | onPopupClose() 122 | return 123 | } 124 | proceedSearch() 125 | if (fetched === false) { 126 | return 127 | } 128 | let keywords = searchText.split(/[-\s]+/) 129 | if (keywords.length > 1) { 130 | keywords.push(searchText) 131 | } 132 | let resultItems = [] 133 | if (searchText.length > 0) { 134 | datas.forEach(data => { 135 | if (!data.title) { 136 | return 137 | } 138 | let TextCount = 0, TitleCount = 0, ContentCount = 0 139 | let title = data.title.trim() 140 | let titleInLowerCase = title.toLowerCase() 141 | let content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : '' 142 | let contentInLowerCase = content.toLowerCase() 143 | let articleUrl = decodeURIComponent(data.url).replace(/\/{2,}/g, '/') 144 | let indexOfTitle = [] 145 | let indexOfContent = [] 146 | keywords.forEach(keyword => { 147 | let hitInTitle = getIndexByWord(keyword, titleInLowerCase, false) 148 | let hitInContent = getIndexByWord(keyword, contentInLowerCase, false) 149 | indexOfTitle = indexOfTitle.concat(hitInTitle) 150 | indexOfContent = indexOfContent.concat(hitInContent) 151 | if (hitInTitle.length > 0 || hitInContent.length > 0) { 152 | TextCount++ 153 | } 154 | if (hitInTitle.length > 0) { 155 | TitleCount++ 156 | } 157 | if (hitInTitle.length > 0 || hitInContent.length > 0) { 158 | ContentCount++ 159 | } 160 | }) 161 | if (indexOfTitle.length > 0 || indexOfContent.length > 0) { 162 | [indexOfTitle, indexOfContent].forEach(index => { 163 | index.sort((itemLeft, itemRight) => { 164 | if (itemRight.position !== itemLeft.position) { 165 | return itemRight.position - itemLeft.position 166 | } 167 | return itemLeft.word.length - itemRight.word.length 168 | }) 169 | }) 170 | 171 | let slicesOfTitle = [] 172 | let slicesOfContent = [] 173 | if (indexOfTitle.length !== 0) { 174 | let tmp = mergeIntoSlice(0, title.length, indexOfTitle, searchText) 175 | slicesOfTitle.push(tmp) 176 | } 177 | let upperBound = parseInt(config.top_n_per_article, 10) 178 | if (upperBound >= 0) { 179 | slicesOfContent = slicesOfContent.slice(0, upperBound) 180 | } 181 | let resultItem = '' 182 | if (slicesOfTitle.length !== 0) { 183 | resultItem += `${highlightKeyword(title, slicesOfTitle[0])}` 184 | } else { 185 | resultItem += `${title}` 186 | } 187 | if (indexOfContent !== null && indexOfContent.length !== 0) { 188 | let item = indexOfContent[indexOfContent.length - 1] 189 | let position = item.position 190 | let word = item.word 191 | let start = position - 20 192 | let end = position + 80 193 | if (start < 0) { 194 | start = 0 195 | } 196 | if (end < position + word.length) { 197 | end = position + word.length 198 | } 199 | if (end > content.length) { 200 | end = content.length 201 | } 202 | let tmp = mergeIntoSlice(start, end, indexOfContent, searchText) 203 | resultItem += `

    ${highlightKeyword(content, tmp)}...

    ` 204 | } else { 205 | resultItem += `

    ${content}...

    ` 206 | } 207 | resultItem += '
    ' 208 | resultItems.push({ 209 | item: resultItem, 210 | TextCount: TextCount, 211 | TitleCount: TitleCount, 212 | ContentCount: ContentCount, 213 | id: resultItems.length 214 | }) 215 | } 216 | }) 217 | } 218 | popup.scroll({ top: 0, left: 0 }) 219 | let resultList = getElement('#search-result') 220 | if (resultItems.length === 0) { 221 | resultList.innerHTML = 222 | `

    ${format(noResult, `${input.value}`)}

    ` 223 | } else { 224 | resultItems.sort((Left, Right) => { 225 | if (Left.TextCount !== Right.TextCount) { 226 | return Right.TextCount - Left.TextCount 227 | } else if (Left.TitleCount !== Right.TitleCount) { 228 | return Right.TitleCount - Left.TitleCount 229 | } else if (Left.ContentCount !== Right.ContentCount) { 230 | return Right.ContentCount - Left.ContentCount 231 | } 232 | return Right.id - Left.id 233 | }) 234 | let searchResultList = "" 235 | resultItems.forEach(result => { 236 | searchResultList += result.item 237 | }) 238 | resultList.innerHTML = searchResultList 239 | } 240 | if (typeof pjax !== 'undefined') { 241 | pjax.refresh(resultList) 242 | } 243 | } 244 | input.addEventListener('keypress', event => { 245 | if (event.key === 13) { 246 | inputEventFunction() 247 | } 248 | }) 249 | let lastEvent = 0 250 | function StartSearch() { 251 | nav.classList.add('search') 252 | nav.classList.add('search-moving') 253 | clearTimeout(lastEvent) 254 | lastEvent = setTimeout(() => nav.classList.remove('search-moving'), 600) 255 | header.closeAll() 256 | if (document.querySelector('.up')) { 257 | getElement('main').style.pointerEvents = 'none' 258 | } 259 | input.placeholder = activeHolder 260 | if (!fetched) { 261 | if (!fetching) { 262 | fetechData() 263 | } 264 | waiting = true 265 | } 266 | } 267 | function EscapeSearch() { 268 | if (!nav.classList.contains('search')) { 269 | return 270 | } 271 | nav.classList.remove('search') 272 | nav.classList.add('search-moving') 273 | clearTimeout(lastEvent) 274 | lastEvent = setTimeout(() => nav.classList.remove('search-moving'), 600) 275 | onPopupClose() 276 | input.value = '' 277 | input.placeholder = blurHolder 278 | document.removeEventListener('mouseup', EscapeSearch) 279 | waiting = false 280 | getElement('main').style.pointerEvents = '' 281 | input.blur() 282 | } 283 | input.addEventListener('keyup', () => { 284 | nav.classList.add('search') 285 | inputEventFunction() 286 | }) 287 | input.addEventListener('focus', () => { 288 | StartSearch() 289 | }) 290 | input.addEventListener('blur', event => { 291 | if (!event.relatedTarget || 292 | event.relatedTarget.parentElement !== getElement('#search-result')) { 293 | EscapeSearch() 294 | } 295 | }) 296 | popup.addEventListener('focusout', event => { 297 | if (!event.relatedTarget || 298 | (event.relatedTarget !== input && 299 | event.relatedTarget.parentElement !== getElement('#search-result'))) { 300 | EscapeSearch() 301 | } 302 | }) 303 | document.addEventListener('keyup', event => { 304 | if (event.key === 'Escape') { 305 | EscapeSearch() 306 | } else if (event.key === 'f' && 307 | !['INPUT', 'TEXTAREA'].includes(event.target.tagName)) { 308 | if (!document.querySelector('.up')) { 309 | getElement('.navBtn').classList.remove('hide') 310 | header.open() 311 | } 312 | StartSearch() 313 | input.focus() 314 | } 315 | }) 316 | document.addEventListener('click', event => { 317 | if (event.target.tagName === 'A' || 318 | event.target.parentElement.tagName === 'A') { 319 | EscapeSearch() 320 | } 321 | }) 322 | })() 323 | -------------------------------------------------------------------------------- /source/lib/encrypt/hbe.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let hbe = () => { 4 | 5 | const cryptoObj = window.crypto || window.msCrypto; 6 | const storage = window.localStorage; 7 | 8 | const storageName = 'hexo-blog-encrypt:#' + window.location.pathname; 9 | 10 | // As we can't detect the wrong password with AES-CBC, 11 | // so adding an empty div and check it when decrption. 12 | const knownPrefix = ""; 13 | 14 | const mainElement = document.getElementById('hexo-blog-encrypt'); 15 | if (mainElement === null) { 16 | return 17 | } 18 | const wrongPassMessage = mainElement.getAttribute('data-wpm'); 19 | const wrongHashMessage = mainElement.getAttribute('data-whm'); 20 | const dataElement = mainElement.getElementsByTagName('script')['hbeData']; 21 | const encryptedData = dataElement.innerText; 22 | const HmacDigist = dataElement.getAttribute('data-hmacdigest'); 23 | // If the plugin version is updated but the blog is not regenerated (e.g. caching), the legacy fixed salt value is used. 24 | const keySalt = dataElement.dataset['keysalt'] ? hexToArray(dataElement.dataset['keysalt']) : textToArray('hexo-blog-encrypt的作者们都是大帅比!'); 25 | const ivSalt = dataElement.dataset['ivsalt'] ? hexToArray(dataElement.dataset['ivsalt']) : textToArray('hexo-blog-encrypt是地表最强Hexo加密插件!'); 26 | 27 | function hexToArray(s) { 28 | return new Uint8Array(s.match(/[\da-f]{2}/gi).map(h => { 29 | return parseInt(h, 16); 30 | })); 31 | } 32 | 33 | function textToArray(s) { 34 | var i = s.length; 35 | var n = 0; 36 | var ba = new Array() 37 | 38 | for (var j = 0; j < i;) { 39 | var c = s.codePointAt(j); 40 | if (c < 128) { 41 | ba[n++] = c; 42 | j++; 43 | } else if ((c > 127) && (c < 2048)) { 44 | ba[n++] = (c >> 6) | 192; 45 | ba[n++] = (c & 63) | 128; 46 | j++; 47 | } else if ((c > 2047) && (c < 65536)) { 48 | ba[n++] = (c >> 12) | 224; 49 | ba[n++] = ((c >> 6) & 63) | 128; 50 | ba[n++] = (c & 63) | 128; 51 | j++; 52 | } else { 53 | ba[n++] = (c >> 18) | 240; 54 | ba[n++] = ((c >> 12) & 63) | 128; 55 | ba[n++] = ((c >> 6) & 63) | 128; 56 | ba[n++] = (c & 63) | 128; 57 | j += 2; 58 | } 59 | } 60 | return new Uint8Array(ba); 61 | } 62 | 63 | function arrayBufferToHex(arrayBuffer) { 64 | if (typeof arrayBuffer !== 'object' || arrayBuffer === null || typeof arrayBuffer.byteLength !== 'number') { 65 | throw new TypeError('Expected input to be an ArrayBuffer') 66 | } 67 | 68 | var view = new Uint8Array(arrayBuffer) 69 | var result = '' 70 | var value 71 | 72 | for (var i = 0; i < view.length; i++) { 73 | value = view[i].toString(16) 74 | result += (value.length === 1 ? '0' + value : value) 75 | } 76 | 77 | return result 78 | } 79 | 80 | async function getExecutableScript(oldElem) { 81 | let out = document.createElement('script'); 82 | const attList = ['type', 'text', 'src', 'crossorigin', 'defer', 'referrerpolicy']; 83 | attList.forEach((att) => { 84 | if (oldElem[att]) 85 | out[att] = oldElem[att]; 86 | }) 87 | 88 | return out; 89 | } 90 | 91 | async function convertHTMLToElement(content) { 92 | let out = document.createElement('div'); 93 | out.innerHTML = content; 94 | out.querySelectorAll('script').forEach(async (elem) => { 95 | elem.replaceWith(await getExecutableScript(elem)); 96 | }); 97 | 98 | return out; 99 | } 100 | 101 | function getKeyMaterial(password) { 102 | let encoder = new TextEncoder(); 103 | return cryptoObj.subtle.importKey( 104 | 'raw', 105 | encoder.encode(password), 106 | { 107 | 'name': 'PBKDF2', 108 | }, 109 | false, 110 | [ 111 | 'deriveKey', 112 | 'deriveBits', 113 | ] 114 | ); 115 | } 116 | 117 | function getHmacKey(keyMaterial) { 118 | return cryptoObj.subtle.deriveKey({ 119 | 'name': 'PBKDF2', 120 | 'hash': 'SHA-256', 121 | 'salt': keySalt.buffer, 122 | 'iterations': 1024 123 | }, keyMaterial, { 124 | 'name': 'HMAC', 125 | 'hash': 'SHA-256', 126 | 'length': 256, 127 | }, true, [ 128 | 'verify', 129 | ]); 130 | } 131 | 132 | function getDecryptKey(keyMaterial) { 133 | return cryptoObj.subtle.deriveKey({ 134 | 'name': 'PBKDF2', 135 | 'hash': 'SHA-256', 136 | 'salt': keySalt.buffer, 137 | 'iterations': 1024, 138 | }, keyMaterial, { 139 | 'name': 'AES-CBC', 140 | 'length': 256, 141 | }, true, [ 142 | 'decrypt', 143 | ]); 144 | } 145 | 146 | function getIv(keyMaterial) { 147 | return cryptoObj.subtle.deriveBits({ 148 | 'name': 'PBKDF2', 149 | 'hash': 'SHA-256', 150 | 'salt': ivSalt.buffer, 151 | 'iterations': 512, 152 | }, keyMaterial, 16 * 8); 153 | } 154 | 155 | async function verifyContent(key, content) { 156 | const encoder = new TextEncoder(); 157 | const encoded = encoder.encode(content); 158 | 159 | let signature = hexToArray(HmacDigist); 160 | 161 | const result = await cryptoObj.subtle.verify({ 162 | 'name': 'HMAC', 163 | 'hash': 'SHA-256', 164 | }, key, signature, encoded); 165 | console.log(`Verification result: ${result}`); 166 | if (!result) { 167 | alert(wrongHashMessage); 168 | console.log(`${wrongHashMessage}, got `, signature, ` but proved wrong.`); 169 | } 170 | return result; 171 | } 172 | 173 | async function decrypt(decryptKey, iv, hmacKey) { 174 | let typedArray = hexToArray(encryptedData); 175 | 176 | const result = await cryptoObj.subtle.decrypt({ 177 | 'name': 'AES-CBC', 178 | 'iv': iv, 179 | }, decryptKey, typedArray.buffer).then(async (result) => { 180 | const decoder = new TextDecoder(); 181 | const decoded = decoder.decode(result); 182 | 183 | // check the prefix, if not then we can sure here is wrong password. 184 | if (!decoded.startsWith(knownPrefix)) { 185 | throw "Decode successfully but not start with KnownPrefix."; 186 | } 187 | 188 | const hideButton = document.createElement('button'); 189 | hideButton.textContent = 'Encrypt again'; 190 | hideButton.type = 'button'; 191 | hideButton.classList.add("hbe-button"); 192 | hideButton.addEventListener('click', () => { 193 | window.localStorage.removeItem(storageName); 194 | window.location.reload(); 195 | }); 196 | 197 | document.getElementById('hexo-blog-encrypt').style.display = 'inline'; 198 | document.getElementById('hexo-blog-encrypt').innerHTML = ''; 199 | document.getElementById('hexo-blog-encrypt').appendChild(await convertHTMLToElement(decoded)); 200 | document.getElementById('hexo-blog-encrypt').appendChild(hideButton); 201 | 202 | // support html5 lazyload functionality. 203 | document.querySelectorAll('img').forEach((elem) => { 204 | if (elem.getAttribute("data-src") && !elem.src) { 205 | elem.src = elem.getAttribute('data-src'); 206 | } 207 | }); 208 | 209 | // support theme-next refresh 210 | window.NexT && NexT.boot && typeof NexT.boot.refresh === 'function' && NexT.boot.refresh(); 211 | 212 | // TOC part 213 | var tocDiv = document.getElementById("toc-div"); 214 | if (tocDiv) { 215 | tocDiv.style.display = ''; 216 | } 217 | 218 | var tocDivs = document.getElementsByClassName('toc-div-class'); 219 | if (tocDivs && tocDivs.length > 0) { 220 | for (var idx = 0; idx < tocDivs.length; idx++) { 221 | tocDivs[idx].style.display = ''; 222 | } 223 | } 224 | 225 | // trigger event 226 | var event = new Event('hexo-blog-decrypt'); 227 | window.dispatchEvent(event); 228 | 229 | return await verifyContent(hmacKey, decoded); 230 | }).catch((e) => { 231 | document.getElementById('hbePass').value = '' 232 | alert(wrongPassMessage); 233 | console.log(e); 234 | return false; 235 | }); 236 | 237 | return result; 238 | 239 | } 240 | 241 | function hbeLoader() { 242 | 243 | const oldStorageData = JSON.parse(storage.getItem(storageName)); 244 | 245 | if (oldStorageData) { 246 | console.log(`Password got from localStorage(${storageName}): `, oldStorageData); 247 | 248 | const sIv = hexToArray(oldStorageData.iv).buffer; 249 | const sDk = oldStorageData.dk; 250 | const sHmk = oldStorageData.hmk; 251 | 252 | cryptoObj.subtle.importKey('jwk', sDk, { 253 | 'name': 'AES-CBC', 254 | 'length': 256, 255 | }, true, [ 256 | 'decrypt', 257 | ]).then((dkCK) => { 258 | cryptoObj.subtle.importKey('jwk', sHmk, { 259 | 'name': 'HMAC', 260 | 'hash': 'SHA-256', 261 | 'length': 256, 262 | }, true, [ 263 | 'verify', 264 | ]).then((hmkCK) => { 265 | decrypt(dkCK, sIv, hmkCK).then((result) => { 266 | if (!result) { 267 | storage.removeItem(storageName); 268 | } 269 | }); 270 | }); 271 | }); 272 | } 273 | 274 | async function tryDecrypt(argument) { 275 | const password = document.getElementById('hbePass').value; 276 | const keyMaterial = await getKeyMaterial(password); 277 | const hmacKey = await getHmacKey(keyMaterial); 278 | const decryptKey = await getDecryptKey(keyMaterial); 279 | const iv = await getIv(keyMaterial); 280 | 281 | decrypt(decryptKey, iv, hmacKey).then((result) => { 282 | console.log(`Decrypt result: ${result}`); 283 | if (result) { 284 | cryptoObj.subtle.exportKey('jwk', decryptKey).then((dk) => { 285 | cryptoObj.subtle.exportKey('jwk', hmacKey).then((hmk) => { 286 | const newStorageData = { 287 | 'dk': dk, 288 | 'iv': arrayBufferToHex(iv), 289 | 'hmk': hmk, 290 | }; 291 | storage.setItem(storageName, JSON.stringify(newStorageData)); 292 | }); 293 | }); 294 | } 295 | }); 296 | } 297 | 298 | mainElement.addEventListener('keydown', async (event) => { 299 | if (event.isComposing || event.keyCode === 13) { 300 | await tryDecrypt(); 301 | } 302 | }); 303 | 304 | mainElement.querySelector('button').addEventListener('click', async () => { 305 | await tryDecrypt(); 306 | }) 307 | } 308 | 309 | hbeLoader(); 310 | 311 | } 312 | 313 | window.addEventListener('DOMContentLoaded', hbe); 314 | document.addEventListener('pjax:success', hbe); 315 | -------------------------------------------------------------------------------- /source/lib/encrypt/hbe.style.css: -------------------------------------------------------------------------------- 1 | .hbe, 2 | .hbe::after, 3 | .hbe::before { 4 | -webkit-box-sizing: border-box; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | } 8 | 9 | .hbe-container{ 10 | margin: 0 auto; 11 | overflow: hidden; 12 | } 13 | .hbe-content { 14 | text-align: center; 15 | font-size: 150%; 16 | padding: 1em 0; 17 | } 18 | 19 | .hbe-input { 20 | position: relative; 21 | z-index: 1; 22 | display: inline-block; 23 | margin: 1em; 24 | width: 80%; 25 | min-width: 200px; 26 | vertical-align: top; 27 | } 28 | 29 | .hbe-input-field { 30 | line-height: normal; 31 | font-size: 100%; 32 | margin: 0; 33 | position: relative; 34 | display: block; 35 | float: right; 36 | padding: 0.8em; 37 | width: 60%; 38 | border: none; 39 | border-radius: 0; 40 | background: #f0f0f0; 41 | color: #aaa; 42 | font-weight: 400; 43 | font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | } 45 | 46 | .hbe-input-field:focus { 47 | outline: none; 48 | } 49 | 50 | .hbe-input-label { 51 | display: inline-block; 52 | padding: 0 1em; 53 | width: 40%; 54 | color: #696969; 55 | font-weight: bold; 56 | font-size: 70.25%; 57 | -webkit-font-smoothing: antialiased; 58 | -moz-osx-font-smoothing: grayscale; 59 | -webkit-touch-callout: none; 60 | -webkit-user-select: none; 61 | -khtml-user-select: none; 62 | -moz-user-select: none; 63 | -ms-user-select: none; 64 | user-select: none; 65 | } 66 | 67 | .hbe-input-label-content { 68 | position: relative; 69 | display: block; 70 | padding: 1.6em 0; 71 | width: 100%; 72 | } 73 | 74 | .hbe-graphic { 75 | position: absolute; 76 | top: 0; 77 | left: 0; 78 | fill: none; 79 | } 80 | 81 | /* hbe button in post page */ 82 | .hbe-button { 83 | display: block; 84 | margin: auto; 85 | padding: 0.75em 1.25em; 86 | outline: none; 87 | border: 1px solid var(--theme-border-light); 88 | border-radius: 5px; 89 | background-color: var(--theme-bg-soft); 90 | color: var(--theme-text-light); 91 | white-space: nowrap; 92 | font-size: 0.75em; 93 | line-height: 1; 94 | transition: 0.3s; 95 | } 96 | 97 | .hbe-button:hover { 98 | border: 1px solid var(--theme-border); 99 | background-color: var(--theme-bg-soft-hover); 100 | color: var(--theme-subcolor); 101 | transition: 0.3s; 102 | } 103 | 104 | .hbe-confirm { 105 | font-weight: bold; 106 | margin-block: 1.8em; 107 | height: 55px; 108 | width: 70px; 109 | background: #666666; 110 | } 111 | .hbe-confirm::before { 112 | content: var(--theme-encrypt-confirm); 113 | } 114 | /* hbe button in post page */ 115 | 116 | /* default theme {{{ */ 117 | .hbe-input-default { 118 | overflow: hidden; 119 | } 120 | 121 | .hbe-input-field-default { 122 | width: 100%; 123 | background: transparent; 124 | padding: 0.5em; 125 | margin-bottom: 2em; 126 | color: #f9f7f6; 127 | z-index: 100; 128 | opacity: 0; 129 | } 130 | 131 | .hbe-input-label-default { 132 | width: 100%; 133 | position: absolute; 134 | text-align: left; 135 | padding: 0.5em 0; 136 | pointer-events: none; 137 | font-size: 1em; 138 | } 139 | 140 | .hbe-input-label-default::before, 141 | .hbe-input-label-default::after { 142 | content: ''; 143 | position: absolute; 144 | width: 100%; 145 | left: 0; 146 | } 147 | 148 | .hbe-input-label-default::before { 149 | height: 100%; 150 | background: #666666; 151 | top: 0; 152 | -webkit-transform: translate3d(0, -100%, 0); 153 | transform: translate3d(0, -100%, 0); 154 | -webkit-transition: -webkit-transform 0.2s; 155 | transition: transform 0.2s; 156 | } 157 | 158 | .hbe-input-label-default::after { 159 | height: 2px; 160 | background: #666666; 161 | top: 100%; 162 | -webkit-transition: opacity 0.2s; 163 | transition: opacity 0.2s; 164 | } 165 | 166 | .hbe-input-label-content-default { 167 | padding: 0; 168 | -webkit-transform-origin: 0 0; 169 | transform-origin: 0 0; 170 | -webkit-transition: -webkit-transform 0.2s, color 0.2s; 171 | transition: transform 0.2s, color 0.2s; 172 | } 173 | 174 | .hbe-input-field-default:focus, 175 | .hbe-input--filled .hbe-input-field-default { 176 | opacity: 1; 177 | -webkit-transition: opacity 0s 0.2s; 178 | transition: opacity 0s 0.2s; 179 | } 180 | 181 | .hbe-input-label-default::before, 182 | .hbe-input-label-default::after, 183 | .hbe-input-label-content-default, 184 | .hbe-input-field-default:focus, 185 | .hbe-input--filled .hbe-input-field-default { 186 | -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); 187 | transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); 188 | } 189 | 190 | .hbe-input-field-default:focus + .hbe-input-label-default::before, 191 | .hbe-input--filled .hbe-input-label-default::before { 192 | -webkit-transform: translate3d(0, 0, 0); 193 | transform: translate3d(0, 0, 0); 194 | } 195 | 196 | .hbe-input-field-default:focus + .hbe-input-label-default::after, 197 | .hbe-input--filled .hbe-input-label-default::after { 198 | opacity: 0; 199 | } 200 | 201 | .hbe-input-field-default:focus + .hbe-input-label-default .hbe-input-label-content-default, 202 | .hbe-input--filled .hbe-input-label-default .hbe-input-label-content-default { 203 | color: #555555; 204 | -webkit-transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); 205 | transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); 206 | } 207 | /* default theme }}} */ 208 | 209 | /* up theme {{{ */ 210 | .hbe-input-up { 211 | overflow: hidden; 212 | padding-top: 2em; 213 | } 214 | 215 | .hbe-input-field-up { 216 | width: 100%; 217 | background: transparent; 218 | opacity: 0; 219 | padding: 0.35em; 220 | z-index: 100; 221 | color: #837482; 222 | } 223 | 224 | .hbe-input-label-up { 225 | width: 100%; 226 | bottom: 0; 227 | position: absolute; 228 | pointer-events: none; 229 | text-align: left; 230 | color: #8E9191; 231 | padding: 0 0.5em; 232 | } 233 | 234 | .hbe-input-label-up::before { 235 | content: ''; 236 | position: absolute; 237 | width: 100%; 238 | height: 4em; 239 | top: 100%; 240 | left: 0; 241 | background: #fff; 242 | border-top: 4px solid #9B9F9F; 243 | -webkit-transform: translate3d(0, -3px, 0); 244 | transform: translate3d(0, -3px, 0); 245 | -webkit-transition: -webkit-transform 0.4s; 246 | transition: transform 0.4s; 247 | -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); 248 | transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); 249 | } 250 | 251 | .hbe-input-label-content-up { 252 | padding: 0.5em 0; 253 | -webkit-transform-origin: 0% 100%; 254 | transform-origin: 0% 100%; 255 | -webkit-transition: -webkit-transform 0.4s, color 0.4s; 256 | transition: transform 0.4s, color 0.4s; 257 | -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); 258 | transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); 259 | } 260 | 261 | .hbe-input-field-up:focus, 262 | .input--filled .hbe-input-field-up { 263 | cursor: text; 264 | opacity: 1; 265 | -webkit-transition: opacity 0s 0.4s; 266 | transition: opacity 0s 0.4s; 267 | } 268 | 269 | .hbe-input-field-up:focus + .hbe-input-label-up::before, 270 | .input--filled .hbe-input-label-up::before { 271 | -webkit-transition-delay: 0.05s; 272 | transition-delay: 0.05s; 273 | -webkit-transform: translate3d(0, -3.3em, 0); 274 | transform: translate3d(0, -3.3em, 0); 275 | } 276 | 277 | .hbe-input-field-up:focus + .hbe-input-label-up .hbe-input-label-content-up, 278 | .input--filled .hbe-input-label-content-up { 279 | color: #6B6E6E; 280 | -webkit-transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); 281 | transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); 282 | } 283 | /* up theme }}} */ 284 | -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /source/lib/fontawesome/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/source/lib/fontawesome/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /support.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yue-plus/hexo-theme-arknights/68f6590ee3933047c471d5dc68c69ec9cc1a942d/support.jpg --------------------------------------------------------------------------------