├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── docs ├── README.md ├── configuration.md ├── features │ ├── img │ │ └── rainbow-banner.png │ ├── latex.md │ ├── rainbow-banner.md │ ├── search.md │ └── tags-and-categories.md └── integrations │ ├── ackee.md │ ├── giscus.md │ ├── img │ └── tidio-integration-url.png │ ├── tidio.md │ └── waline.md ├── languages ├── default.yml └── zh-cn.yml ├── layout ├── _partial │ ├── categories.ejs │ ├── footer.ejs │ ├── head.ejs │ ├── nav.ejs │ ├── paginator.ejs │ ├── search.ejs │ └── tags.ejs ├── archive.ejs ├── index.ejs ├── layout.ejs └── post.ejs ├── scripts └── merge-config.js └── source ├── css ├── archive.css ├── categories.css ├── code-highlighting.css ├── components.css ├── footer.css ├── giscus.css ├── index.css ├── main.css ├── nav.css ├── paginator.css ├── post-list.css ├── post.css ├── rainbow-banner.css ├── search.css ├── tags.css ├── toc.css ├── typography.css └── var.css ├── js ├── main.js ├── search.js └── tidio.js └── theme-img ├── discord-mark-dark.svg ├── discord-mark-light.svg ├── github-mark-dark.png ├── github-mark-light.png ├── mastodon-logo-black.svg ├── mastodon-logo-white.svg ├── patreon-logo-black.png ├── patreon-logo-white.png ├── search-dark.svg ├── search-light.svg ├── tags-dark.svg └── tags-light.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mr. Will 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.md: -------------------------------------------------------------------------------- 1 | > [!TIP] 2 | > Updates are landing on branch [`next`](https://github.com/MrWillCom/hexo-theme-cupertino/tree/next), check it out to preview the latest features and improvements that will be released in v2. ✨ 3 | 4 | --- 5 | 6 | # Hexo Theme Cupertino 7 | 8 | The Hexo Blog Theme Cupertino 9 | 10 | ![A screenshot](https://mrwillcom.github.io/img/000001.png) 11 | 12 | Visit [blog.mrwillcom.com](https://blog.mrwillcom.com/) to preview it. 13 | 14 | This theme is based on Cupertino Design with light border and translucent and acrylic background on navigation bar, supports dark appearance and powerful footer. 15 | 16 | ## Installation 17 | 18 | If you don't have a [Hexo](https://hexo.io/) blog, just [create one](https://hexo.io/docs/). 19 | 20 | To install it, just clone this as a Git submodule to your `themes/cupertino/` directory and edit your `_config.yml`. After that, you should remember to edit `themes/cupertino/_config.yml`. 21 | 22 | `_config.yml`: 23 | ```yaml 24 | ... 25 | theme: cupertino 26 | ... 27 | ``` 28 | 29 | ## Further Configuration 30 | 31 | See docs site [cupertino.mrwillcom.com](https://cupertino.mrwillcom.com/) . 32 | 33 | ## Contributing 34 | 35 | All friendly contributions are welcome! Start contributing by following the existing issues or little fixes. 36 | 37 | Not familiar with code? It's okay, feel free to report bugs or suggest something. 38 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # REMEMBER TO EDIT THIS BEFORE DEPLOYING!!! 2 | 3 | # the path to your blog's icon: 4 | favicon: /favicon.png 5 | 6 | # the path to manifest.json 7 | manifest: /manifest.json 8 | 9 | # [Open Graph Protocol](https://ogp.me/) 10 | og_enabled: true 11 | og_image: /favicon.png 12 | og: 13 | # customize og properties here which will replace the defaults 14 | 15 | # show excerpt on post list 16 | show_excerpt: false 17 | 18 | # light/dark/auto color scheme 19 | color_scheme: auto 20 | 21 | # show floating color theme toggle 22 | show_color_scheme_toggle: true 23 | 24 | # uppercase categories 25 | uppercase_categories: true 26 | 27 | # capitalize tag names on tags page 28 | capitalize_tags: false 29 | 30 | # add hashtag prefix before tags 31 | hashtag_prefix_before_tags: true 32 | 33 | # rainbow! 34 | rainbow_banner: true 35 | rainbow_banner_colors: 36 | - '#e50000' 37 | - '#ff8d00' 38 | - '#ffee00' 39 | - '#008121' 40 | - '#004cff' 41 | - '#760188' 42 | # choose from [auto, always] 43 | rainbow_banner_shown: auto 44 | # Pride Month by default 45 | rainbow_banner_month: 6 46 | 47 | # TOC - table of contents 48 | toc: true 49 | toc_max_depth: 2 50 | 51 | # scroll reveal (https://scrollrevealjs.org/) - animating elements as they enter/leave the viewport 52 | scroll_reveal: true 53 | 54 | # navigation config 55 | nav: 56 | # the title displays in the upper left corner which won't change 57 | title: Blog 58 | # the items displays in the upper right corner 59 | items: 60 | # these items will display as a link 61 | Archives: /archives 62 | Friends: /friends 63 | Projects: /projects 64 | About: /about 65 | # these will be automatically be an icon 66 | GitHub: https://github.com/MrWillCom 67 | CodePen: https://codepen.io/mrwillcom 68 | Patreon: https://www.patreon.com/MrWillCom 69 | Mastodon: https://noc.social/@MrWillCom 70 | Discord: https://discord.gg/UKuFDjcfY8 71 | Search: /search 72 | 73 | # footer items 74 | footer: 75 | # the title 76 | Blog: 77 | # the items after the title, display as links 78 | Blog: / 79 | Archives: /archives 80 | Tags: /tags 81 | Categories: /categories 82 | Search: /search 83 | Friends: /friends 84 | Projects: /projects 85 | Resume: /resume 86 | About: /about 87 | RSS: /atom.xml 88 | # also the title 89 | Projects: 90 | # the items 91 | RSA CLI: https://github.com/MrWillCom/rsa-cli 92 | Hexo Theme Cupertino: https://github.com/MrWillCom/hexo-theme-cupertino 93 | A Calendar: https://github.com/MrWillCom/a-calendar 94 | Auto Mirroring Bucket: https://github.com/MrWillCom/auto-mirroring-bucket 95 | # the title 96 | Me: 97 | # items 98 | GitHub: https://github.com/MrWillCom 99 | CodePen: https://codepen.io/mrwillcom 100 | Patreon: https://www.patreon.com/MrWillCom 101 | Mastodon: https://noc.social/@MrWillCom 102 | Discord: https://discord.gg/UKuFDjcfY8 103 | Email: mailto:mr.will.com@outlook.com 104 | 105 | # footer extra description 106 | # footer_extra_description: something will be shown at the bottom of the footer 107 | 108 | # the license your posts under 109 | license: CC BY-NC 4.0 110 | # the link of your license 111 | license_link: https://creativecommons.org/licenses/by-nc/4.0 112 | 113 | # search 114 | # based on [hexo-generator-search](https://github.com/wzpan/hexo-generator-search) 115 | search: true 116 | search_path: search.json 117 | 118 | # REMEMBER TO EDIT THIS BEFORE DEPLOYING!!! -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | To edit `themes/cupertino/_config.yml`, just read the comments in it. 4 | 5 | ## Optional & Advanced Features 6 | 7 | Some features are optional and requires further configuration, so check out the following docs. 8 | 9 | - [Tags and Categories](./features/tags-and-categories.md) 10 | - [Search](./features/search.md) 11 | - [LaTeX](./features/latex.md) 12 | - [Rainbow Banner](./features/rainbow-banner.md) 13 | 14 | ## Integrations 15 | 16 | You can integrate these services to your blog: 17 | 18 | - [Tidio](./integrations/tidio.md) 19 | - [Waline](./integrations/waline.md) 20 | - [giscus](./integrations/giscus.md) 21 | - [Ackee](./integrations/ackee.md) 22 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | To know how to edit `themes/cupertino/_config.yml`, just read the comments in it. 4 | 5 | ## Optional Features 6 | 7 | Some features are not enabled by default, and you need to enable it on your own. 8 | 9 | - [LaTeX](./features/latex.md) 10 | 11 | ## Integrations 12 | 13 | You can integrate these services to your blog: 14 | 15 | - [Tidio](./integrations/tidio.md) 16 | - [Waline](./integrations/waline.md) 17 | - [giscus](./integrations/giscus.md) 18 | - [Ackee](./integrations/ackee.md) 19 | -------------------------------------------------------------------------------- /docs/features/img/rainbow-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/docs/features/img/rainbow-banner.png -------------------------------------------------------------------------------- /docs/features/latex.md: -------------------------------------------------------------------------------- 1 | # LaTeX 2 | 3 | You don't need to change any theme config exactly, and you can choose the renderer you like from the following: 4 | 5 | - [hexo-math](https://github.com/hexojs/hexo-math) 6 | - [Hexo Filter MathJax](https://github.com/next-theme/hexo-filter-mathjax) 7 | 8 | Just follow their documentation to install them, no further configuration required. 9 | 10 | > Plot $(x^2 + y^2 -1)^3 -x^2 y^3 = 0$. 💖 from [@aeilot's PR](https://github.com/MrWillCom/hexo-theme-cupertino/pull/9) 11 | -------------------------------------------------------------------------------- /docs/features/rainbow-banner.md: -------------------------------------------------------------------------------- 1 | # 🌈 Rainbow Banner 2 | 3 | ![A screenshot of rainbow banner](./img/rainbow-banner.png) 4 | 5 | Rainbow banner is enabled by default, and will only appear every June. You can customize it on your own to show your pride. 6 | 7 | This is the default config: 8 | 9 | ```yaml 10 | # rainbow! 11 | rainbow_banner: true 12 | rainbow_banner_colors: 13 | - '#e50000' 14 | - '#ff8d00' 15 | - '#ffee00' 16 | - '#008121' 17 | - '#004cff' 18 | - '#760188' 19 | # choose from [auto, always] 20 | rainbow_banner_shown: auto 21 | # Pride Month by default 22 | rainbow_banner_month: 6 23 | ``` 24 | 25 | ## `rainbow_banner` 26 | 27 | A `boolean`, the main switch of this feature. When `false`, all the configurations below will make no effects. 28 | 29 | ## `rainbow_banner_colors` 30 | 31 | An `Array` of the colors of rainbow, from left to right, and has no amount limitation. 32 | 33 | ## `rainbow_banner_shown` 34 | 35 | Choose from `auto` and `always`. If `always`, the rainbow banner will be shown at anytime. If `auto`, the banner will only be shown in `rainbow_banner_month`. 36 | 37 | ## `rainbow_banner_month` 38 | 39 | A `Number` between `[1, 12]`, the month when the rainbow banner will be shown, only works with `rainbow_banner_shown: auto`. 40 | -------------------------------------------------------------------------------- /docs/features/search.md: -------------------------------------------------------------------------------- 1 | # Search 2 | 3 | Search features are enabled by default, but requires a few steps to make it available. 4 | 5 | 1. Run 6 | ```sh 7 | # [hexo-generator-search](https://github.com/wzpan/hexo-generator-search) 8 | $ npm install hexo-generator-search --save 9 | ``` 10 | 2. Add these lines to blog configuration `_config.yml`: 11 | ```yml 12 | search: 13 | path: search.json 14 | content: false 15 | ``` 16 | 3. Add new search page so that Hexo will generate it. 17 | ```sh 18 | $ hexo new page 'search' 19 | ``` 20 | 4. Replace all its content with: 21 | ```markdown 22 | --- 23 | type: search 24 | --- 25 | ``` 26 | 27 | Done! Your search page is ready at `/search/`. 28 | -------------------------------------------------------------------------------- /docs/features/tags-and-categories.md: -------------------------------------------------------------------------------- 1 | # Tags and Categories 2 | 3 | Tags and categories features are enabled by default. But only part of them are available with zero-config. To make full use of them, follow the instructions: 4 | 5 | ## Tags and Categories Page 6 | 7 | Firstly, run these commands: 8 | 9 | ```sh 10 | $ hexo new page 'tags' 11 | $ hexo new page 'categories' 12 | ``` 13 | 14 | Then, you should get two new files at `source/tags/index.md` and `source/categories/index.md`. Replace all of their content with the following: 15 | 16 | `source/tags/index.md` 17 | 18 | ```markdown 19 | --- 20 | type: tags 21 | --- 22 | ``` 23 | 24 | `source/categories/index.md` 25 | 26 | ```markdown 27 | --- 28 | type: categories 29 | --- 30 | ``` 31 | 32 | Done! Now, `/tags/` and `/categories/` pages will be generated correctly. 33 | -------------------------------------------------------------------------------- /docs/integrations/ackee.md: -------------------------------------------------------------------------------- 1 | # Ackee Integration 2 | 3 | It's such a simple thing to add Ackee to your blog, just copy `` and put it here like this: 4 | 5 | ```yml 6 | ackee: 7 | 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/integrations/giscus.md: -------------------------------------------------------------------------------- 1 | # giscus Integration 2 | 3 | It's so simple to add giscus to your blog, just get `` and paste it here: 4 | 5 | ```yml 6 | giscus: 7 | 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/integrations/img/tidio-integration-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/docs/integrations/img/tidio-integration-url.png -------------------------------------------------------------------------------- /docs/integrations/tidio.md: -------------------------------------------------------------------------------- 1 | # Tidio Integration 2 | 3 | We support installing Tidio to your blog. 4 | 5 | 1. Go to [Tidio Settings/Channels/Live Chat/Integration](https://www.tidio.com/panel/settings/live-chat/integration). 6 | 2. Click "click here". 7 | 3. Select "JavaScript". 8 | 4. Copy the URL in the code it provided. 9 | ![Screenshot of the settings page and the integration url](./img/tidio-integration-url.png) 10 | 5. Add `tidio` property to your blog configuration `_config.yml`: 11 | ```yml 12 | ... 13 | tidio: 14 | ... 15 | ``` 16 | 6. Done! 17 | -------------------------------------------------------------------------------- /docs/integrations/waline.md: -------------------------------------------------------------------------------- 1 | # Waline Integration 2 | 3 | We support installing Waline to your blog. 4 | 5 | Add `waline` property to your blog configuration `_config.yml`: 6 | 7 | ```yml 8 | waline: 9 | # Don't set `el` here. 10 | path: location.pathname 11 | serverURL: "'https://example.com'" 12 | requiredMeta: "['nick', ...]" 13 | ``` 14 | 15 | All the sub-properties are the same as the script in [HTML References - Quick Start | Waline](https://waline.js.org/en/quick-start.html#html-references) except `el`. 16 | 17 | You should not set `el` property, it must match the EJS document. 18 | -------------------------------------------------------------------------------- /languages/default.yml: -------------------------------------------------------------------------------- 1 | latest_posts: Latest Posts 2 | read_more: Read More 3 | powered_by: Powered by %s 4 | prev: Prev 5 | next: Next 6 | archives: Archives 7 | about_this_post: About this Post 8 | this_post_is_written_by: This post is written by %s 9 | licensed_under: licensed under %s 10 | home: Home 11 | category: Category 12 | tag: Tag 13 | tagged_with: Tagged with %s 14 | search: Search 15 | type_to_search: Type to search... 16 | categories: Categories 17 | tags: Tags 18 | next_post: Next 19 | prev_post: Previous 20 | -------------------------------------------------------------------------------- /languages/zh-cn.yml: -------------------------------------------------------------------------------- 1 | latest_posts: 最新文章 2 | read_more: 继续阅读 3 | powered_by: 由 %s 驱动 4 | prev: 上一页 5 | next: 下一页 6 | archives: 存档 7 | about_this_post: 关于本文 8 | this_post_is_written_by: 由 %s 撰写 9 | licensed_under: 采用 %s 许可协议 10 | home: 主页 11 | category: 分类 12 | tag: 标签 13 | tagged_with: 打上了 %s 的标签 14 | search: 搜索 15 | type_to_search: 键入以搜索... 16 | categories: 分类 17 | tags: 标签 18 | next_post: 下一篇 19 | prev_post: 上一篇 20 | -------------------------------------------------------------------------------- /layout/_partial/categories.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= __('categories') %>

4 |
5 |
6 |
7 | <% 8 | var categories = '' 9 | site.categories.forEach((category) => { 10 | categories += `${category.name}` 11 | }) 12 | %> 13 | <%- categories %> 14 |
15 |
-------------------------------------------------------------------------------- /layout/_partial/footer.ejs: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /layout/_partial/head.ejs: -------------------------------------------------------------------------------- 1 | prefix="og: https://ogp.me/ns#"<% } %>> 2 | 3 | 4 | 5 | <% 6 | var title = page.title; 7 | 8 | if (is_archive()){ 9 | title = __('archives'); 10 | 11 | if (is_month()){ 12 | title += ': ' + page.year + '/' + page.month; 13 | } else if (is_year()){ 14 | title += ': ' + page.year; 15 | } 16 | } else if (is_category()){ 17 | title = __('category') + ': ' + page.category; 18 | } else if (is_tag()){ 19 | if (theme.hashtag_prefix_before_tags) { 20 | title = '#' + page.tag; 21 | } else { 22 | title = __('tag') + ': ' + page.tag; 23 | } 24 | } else if (theme.search == true && page.type == 'search') { 25 | title = __('search') 26 | } else if (page.type == 'tags') { 27 | title = __('tags'); 28 | } else if (page.type == 'categories') { 29 | title = __('categories'); 30 | } 31 | %> 32 | <% if (title){ %><%= title %> - <% } %><%= config.title %> 33 | <% if (theme.favicon){ %> 34 | <%- favicon_tag(theme.favicon) %> 35 | <% } %> 36 | <% if (theme.manifest) { %> 37 | 38 | <% } %> 39 | 40 | <% if (theme.og_enabled) { %> 41 | <% 42 | var og = {}; 43 | 44 | og['title'] = (title ? title + ' - ' : '') + config.title; 45 | og['type'] = is_post() ? 'article' : 'website'; 46 | og['url'] = url; 47 | og['image'] = page.cover_image ? page.cover_image : theme.og_image; 48 | if (is_post()) { 49 | og['article:published_time'] = page.date.toISOString(); 50 | og['article:author'] = config.author; 51 | } 52 | 53 | if (theme['og']) { 54 | for (const i in theme.og) { 55 | og[i] = theme.og[i]; 56 | } 57 | } 58 | 59 | if (page['og']) { 60 | for (const i in page.og) { 61 | og[i] = page.og[i]; 62 | } 63 | } 64 | %> 65 | <% for (const i in og) { %> 66 | 67 | <% } %> 68 | <% } %> 69 | 70 | <%- css('css/var') %> 71 | <%- css('css/main') %> 72 | <%- css('css/typography') %> 73 | <%- css('css/code-highlighting') %> 74 | <%- css('css/components') %> 75 | <%- css('css/nav') %> 76 | <%- css('css/paginator') %> 77 | <%- css('css/footer') %> 78 | <%- css('css/post-list') %> 79 | <% if (theme.rainbow_banner) { %> 80 | <%- css('css/rainbow-banner') %> 81 | <% } %> 82 | <% if (theme.toc) { %> 83 | <%- css('css/toc') %> 84 | <% } %> 85 | <% if (config.giscus) { %> 86 | <%- css('css/giscus') %> 87 | <% } %> 88 | <% if (page.path == "index.html") { %> 89 | <%- css('css/index') %> 90 | <% } %> 91 | <% if (page.path != "index.html") { %> 92 | <%- css('css/post') %> 93 | <% } %> 94 | <% if (is_archive() || is_category() || is_tag() || (theme.search == true && page.type == 'search') || page.type == 'tags' || page.type == 'categories') { %> 95 | <%- css('css/archive') %> 96 | <% } %> 97 | <% if (theme.search == true && page.type == 'search') { %> 98 | <%- css('css/search') %> 99 | <% } %> 100 | <% if (page.type == 'tags') { %> 101 | <%- css('css/tags') %> 102 | <% } %> 103 | <% if (page.type == 'categories') { %> 104 | <%- css('css/categories') %> 105 | <% } %> 106 | 107 | <% if (config.waline) { %> 108 | 109 | 113 | <% } %> 114 | -------------------------------------------------------------------------------- /layout/_partial/nav.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layout/_partial/paginator.ejs: -------------------------------------------------------------------------------- 1 | <% if (page.total > 1){ %> 2 |
3 | <%- paginator({ 4 | prev_text: "" + __('prev'), 5 | next_text: __('next') + "" 6 | }) %> 7 |
8 | <% } %> -------------------------------------------------------------------------------- /layout/_partial/search.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | <%= __('search') %> 5 |

6 |
7 |
8 | 9 |
10 |
11 |
-------------------------------------------------------------------------------- /layout/_partial/tags.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= __('tags') %>

4 |
5 |
6 |
7 | <% 8 | var tags = '' 9 | site.tags.forEach((tag) => { 10 | tags += `${theme.hashtag_prefix_before_tags ? '#' : ''}${tag.name}${theme.hashtag_prefix_before_tags ? '' : ','}` 11 | }) 12 | if (!theme.hashtag_prefix_before_tags) { tags = tags.slice(0, tags.length - 1) } 13 | %> 14 | <%- tags %> 15 |
16 |
-------------------------------------------------------------------------------- /layout/archive.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layout/index.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layout/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- partial('_partial/head') %> 4 | 8 | data-rainbow-banner="<%= theme.rainbow_banner %>" 9 | data-rainbow-banner-shown="<%= theme.rainbow_banner_shown %>" 10 | data-rainbow-banner-month="<%= theme.rainbow_banner_month %>" 11 | data-rainbow-banner-colors="<%= theme.rainbow_banner_colors %>" 12 | <% } %> 13 | data-config-root="<%- config.root %>" 14 | <% if (theme.toc == true) { %> 15 | data-toc="<%= theme.toc %>" 16 | data-toc-max-depth="<%= theme.toc_max_depth %>" 17 | <% } %> 18 | <% if (theme.search == true && page.type == 'search') { %> 19 | data-search-path="<%= theme.search_path %>" 20 | <% } %> 21 | > 22 | <%- partial('_partial/nav') %> 23 | <%- body %> 24 | <%- partial('_partial/footer') %> 25 | 26 | <%- js('js/main.js') %> 27 | <% if (theme.search == true && page.type == 'search') { %> 28 | <%- js('js/search.js') %> 29 | <% } %> 30 | <% if (config.tidio) { %> 31 | <%- js(config.tidio) %> 32 | <%- js('js/tidio.js') %> 33 | <% } %> 34 | <% if (config.ackee) { %> 35 | <%- config.ackee %> 36 | <% } %> 37 | 38 | <% if (theme.scroll_reveal) { %> 39 | 40 | 47 | <% } %> 48 | 49 | -------------------------------------------------------------------------------- /layout/post.ejs: -------------------------------------------------------------------------------- 1 | <% if (theme.search == true && page.type == 'search') { %> 2 | <%- partial('_partial/search') %> 3 | <% } else if (page.type == 'tags') { %> 4 | <%- partial('_partial/tags') %> 5 | <% } else if (page.type == 'categories') { %> 6 | <%- partial('_partial/categories') %> 7 | <% } else { %> 8 |
9 |
10 | <% if (page.categories && page.categories.length) { %> 11 |
12 | <% page.categories.forEach((category) => { %> 13 | <%= category.name %> 14 | <% }) %> 15 |
16 | <% } %> 17 | 18 | <% if (!page.no_date) { %> 19 |
20 | <%= ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][page.date.month()] %> 21 | <%- page.date.date() %>, 22 | <%- page.date.year() %> 23 |
24 | <% } %> 25 | 26 |

<%= page.title %>

27 |
28 | 29 |
30 | 31 |
32 | <%- page.content %> 33 |
34 | 35 | <% if (!page.no_about) { %> 36 |
37 |

<%= __('about_this_post') %>

38 |
39 |

<%- __('this_post_is_written_by', config.author) %>, <%- __('licensed_under', `${theme.license}`) %>.

40 |
41 | <% if (page.tags && page.tags.length) { %> 42 |

43 | <% 44 | var tags = '' 45 | page.tags.forEach((tag) => { 46 | tags += `${theme.hashtag_prefix_before_tags ? '#' : ''}${tag.name}${theme.hashtag_prefix_before_tags ? '' : ','}` 47 | }) 48 | if (!theme.hashtag_prefix_before_tags) { tags = tags.slice(0, tags.length - 1) } 49 | %> 50 | 51 | <%- tags %> 52 |

53 | <% } %> 54 |
55 | <% } %> 56 | 57 |
58 | <% if (page.prev) { %> 59 | 67 | <% } else { %><% } %> 68 | <% if (page.next) { %> 69 | 77 | <% } else { %><% } %> 78 |
79 | 80 | <% if (!page.no_comments) { %> 81 | <% if (config.waline) { %> 82 |
83 |
84 | 92 |
93 | <% } %> 94 | <% if (config.giscus) { %> 95 | <%- config.giscus %> 96 | <% } %> 97 | <% } %> 98 |
99 | <% } %> -------------------------------------------------------------------------------- /scripts/merge-config.js: -------------------------------------------------------------------------------- 1 | // Inspired by Hexo Theme Volantis 2 | // [hexo-theme-volantis/scripts/events/lib/config.js](https://github.com/volantis-x/hexo-theme-volantis/blob/8d2394aa3e8a665702f26a686e85adcf59cd114d/scripts/events/lib/config.js) 3 | // [MIT](https://github.com/volantis-x/hexo-theme-volantis/blob/8d2394aa3e8a665702f26a686e85adcf59cd114d/LICENSE) Licensed 4 | 5 | hexo.on('generateBefore', () => { 6 | const isObject = v => { 7 | return v && typeof v === 'object' && !Array.isArray(v) 8 | } 9 | 10 | const merge = (target, source) => { 11 | for (const key in source) { 12 | if (isObject(target[key]) && isObject(source[key])) { 13 | merge(target[key], source[key]) 14 | } else { 15 | target[key] = source[key] 16 | } 17 | } 18 | 19 | return target 20 | } 21 | 22 | merge(hexo.theme.config, hexo.config.theme_config) 23 | }) 24 | -------------------------------------------------------------------------------- /source/css/archive.css: -------------------------------------------------------------------------------- 1 | .meta { 2 | margin-top: 128px; 3 | } 4 | 5 | .meta .type { 6 | color: var(--grey); 7 | font-weight: 600; 8 | max-width: 800px; 9 | margin-left: auto; 10 | margin-right: auto; 11 | padding: 0 16px; 12 | } 13 | -------------------------------------------------------------------------------- /source/css/categories.css: -------------------------------------------------------------------------------- 1 | .categories { 2 | margin-bottom: 128px; 3 | display: grid; 4 | grid-template-columns: 1fr 1fr 1fr; 5 | } 6 | 7 | @media screen and (max-width: 800px) { 8 | .categories { 9 | grid-template-columns: 1fr 1fr; 10 | } 11 | } 12 | 13 | .categories .category { 14 | display: block; 15 | padding: 12px 24px; 16 | margin: 6px; 17 | font-size: 20px; 18 | font-weight: bold; 19 | border-radius: 12px; 20 | background-color: var(--white); 21 | color: var(--black-2); 22 | text-decoration: none; 23 | border: 1px solid var(--border-color); 24 | } 25 | 26 | .categories .category:hover { 27 | background-color: var(--white-1); 28 | color: var(--black); 29 | } 30 | -------------------------------------------------------------------------------- /source/css/code-highlighting.css: -------------------------------------------------------------------------------- 1 | /* This Code Highlighting Theme is based on GitHub Theme */ 2 | 3 | .gutter { 4 | color: var(--grey); 5 | user-select: none; 6 | } 7 | 8 | .highlight .name { 9 | color: #22863a; 10 | } 11 | 12 | .highlight .attr, .highlight .meta, .highlight .meta-keyword, .highlight .attribute, .highlight .number, .highlight .selector-class { 13 | color: #005cc5 14 | } 15 | 16 | .highlight .string { 17 | color: #032f62; 18 | } 19 | 20 | .highlight .symbol { 21 | color: #005cc5; 22 | } 23 | 24 | .highlight .selector-tag { 25 | color: #22863a; 26 | } 27 | 28 | .highlight .built_in { 29 | color: #6f42c1; 30 | } 31 | 32 | .highlight .keyword { 33 | color: #d73a49; 34 | } 35 | 36 | @media (prefers-color-scheme: dark) { 37 | .highlight .name { 38 | color: #7ee787; 39 | } 40 | .highlight .attr, .highlight .meta, .highlight .meta-keyword, .highlight .attribute, .highlight .number, .highlight .selector-class { 41 | color: #79c0ff 42 | } 43 | .highlight .string { 44 | color: #a5d6ff; 45 | } 46 | .highlight .symbol { 47 | color: #79b8ff; 48 | } 49 | .highlight .selector-tag { 50 | color: #7ee787; 51 | } 52 | .highlight .built_in { 53 | color: #d2a8ff; 54 | } 55 | .highlight .keyword { 56 | color: #ff7b72; 57 | } 58 | } -------------------------------------------------------------------------------- /source/css/components.css: -------------------------------------------------------------------------------- 1 | .card-grid { 2 | display: grid; 3 | grid-template-columns: 1fr 1fr 1fr; 4 | } 5 | 6 | .card-grid { 7 | max-width: 1000px; 8 | margin: auto; 9 | padding: 0 16px; 10 | } 11 | 12 | @media screen and (max-width: 1000px) { 13 | .card-grid { 14 | max-width: 800px; 15 | } 16 | } 17 | 18 | @media screen and (max-width: 800px) { 19 | .card-grid { 20 | grid-template-columns: 1fr 1fr; 21 | } 22 | } 23 | 24 | @media screen and (max-width: 600px) { 25 | .card-grid { 26 | display: block; 27 | } 28 | } 29 | 30 | .card { 31 | overflow: hidden; 32 | border-radius: 16px; 33 | background-color: var(--card-bg); 34 | margin-bottom: 21px; 35 | transition: all 200ms ease; 36 | } 37 | 38 | .card:nth-child(3n-2) { 39 | margin-left: 0; 40 | margin-right: 8px; 41 | } 42 | 43 | .card:nth-child(3n-1) { 44 | margin-left: 8px; 45 | margin-right: 8px; 46 | } 47 | 48 | .card:nth-child(3n) { 49 | margin-left: 8px; 50 | margin-right: 0; 51 | } 52 | 53 | @media screen and (max-width: 800px) { 54 | .card:nth-child(2n-1) { 55 | margin-left: 0; 56 | margin-right: 8px; 57 | } 58 | .card:nth-child(2n) { 59 | margin-left: 8px; 60 | margin-right: 0; 61 | } 62 | } 63 | 64 | @media screen and (max-width: 600px) { 65 | .card { 66 | margin-left: 0px!important; 67 | margin-right: 0px!important; 68 | } 69 | } 70 | 71 | .card .cover-img { 72 | overflow: hidden; 73 | height: 266px; 74 | } 75 | 76 | .card .cover-img img { 77 | width: 100%; 78 | height: 100%; 79 | object-fit: cover; 80 | filter: brightness(1); 81 | transition: transform 400ms cubic-bezier(0.4, 0, 0.25, 1), filter 400ms cubic-bezier(0.4, 0, 0.25, 1); 82 | } 83 | 84 | .card:hover .cover-img img { 85 | transform: scale(1.03); 86 | filter: brightness(0.85); 87 | } 88 | 89 | .card .content { 90 | padding: 18px; 91 | } 92 | 93 | .card .title { 94 | font-weight: bold; 95 | font-size: 24px; 96 | color: var(--black); 97 | text-decoration: none; 98 | padding: 0; 99 | } 100 | 101 | .card .description { 102 | font-size: 17px; 103 | color: var(--black-1); 104 | padding: 0; 105 | } 106 | 107 | .card .actions { 108 | padding: 16px; 109 | padding-top: 0; 110 | display: flex; 111 | } 112 | 113 | .card .actions .left { 114 | justify-content: flex-start; 115 | } 116 | 117 | .card .actions .right { 118 | margin-left: auto; 119 | justify-content: flex-end; 120 | } 121 | 122 | .actions .action-button-primary { 123 | background-color: var(--blue); 124 | color: var(--white-txt-on-blue-bg); 125 | padding: 6px 12px; 126 | border-radius: 32px; 127 | text-decoration: none; 128 | transition: 0.5s; 129 | } 130 | 131 | .actions .action-button-primary:hover { 132 | background-color: var(--link); 133 | } 134 | 135 | .block-large { 136 | max-width: 1000px; 137 | margin: auto; 138 | } 139 | 140 | .badge { 141 | --color: var(--link); 142 | font-size: 16px; 143 | border: 2px solid var(--color); 144 | color: var(--color); 145 | padding: 0 8px; 146 | margin: 0 6px; 147 | border-radius: 24px; 148 | } 149 | 150 | .badge.warning { 151 | --color: #fdc008; 152 | } 153 | 154 | .badge.secondary { 155 | --color: #6c7781; 156 | } 157 | 158 | .badge.success { 159 | --color: #31b14e; 160 | } 161 | 162 | .no-select { 163 | user-select: none; 164 | } 165 | 166 | .text-left { 167 | text-align: left; 168 | } 169 | 170 | .text-center { 171 | text-align: center; 172 | } 173 | 174 | .text-right { 175 | text-align: right; 176 | } 177 | 178 | .text-uppercase { 179 | text-transform: uppercase; 180 | } 181 | 182 | .text-lowercase { 183 | text-transform: lowercase; 184 | } 185 | 186 | .text-capitalize { 187 | text-transform: capitalize; 188 | } 189 | -------------------------------------------------------------------------------- /source/css/footer.css: -------------------------------------------------------------------------------- 1 | footer { 2 | background-color: var(--white); 3 | width: 100%; 4 | border-top: 1px solid var(--border-color); 5 | user-select: none; 6 | } 7 | 8 | .inner { 9 | max-width: 980px; 10 | margin: auto; 11 | padding: 32px 16px; 12 | } 13 | 14 | footer .links { 15 | display: grid; 16 | grid-template-columns: 1fr 1fr 1fr; 17 | } 18 | 19 | @media screen and (max-width: 600px) { 20 | footer .links { 21 | grid-template-columns: 1fr 1fr; 22 | } 23 | } 24 | 25 | @media screen and (max-width: 400px) { 26 | footer .links { 27 | grid-template-columns: 1fr; 28 | } 29 | } 30 | 31 | footer .group { 32 | margin: 0; 33 | margin-bottom: 16px; 34 | } 35 | 36 | footer .title { 37 | font-size: 17px; 38 | margin: 0; 39 | margin-bottom: 8px; 40 | } 41 | 42 | footer .item { 43 | color: var(--footer-link-grey); 44 | display: block; 45 | } 46 | 47 | footer .footer-extra-description { 48 | color: var(--footer-link-grey); 49 | font-size: 14px; 50 | display: block; 51 | margin-top: 12px; 52 | margin-bottom: -12px; 53 | } 54 | 55 | footer .color-scheme-toggle { 56 | display: flex; 57 | padding: 1px; 58 | gap: 1px; 59 | border-radius: 16px; 60 | border: 1px solid var(--blue); 61 | margin-top: 16px; 62 | width: max-content; 63 | } 64 | 65 | footer .color-scheme-toggle label { 66 | display: flex; 67 | } 68 | 69 | footer .color-scheme-toggle label input { 70 | position: absolute; 71 | width: 0px; 72 | height: 0px; 73 | margin: 0; 74 | } 75 | 76 | footer .color-scheme-toggle label span { 77 | font-size: 12px; 78 | padding: 4px 2px; 79 | border-radius: 12px; 80 | color: var(--link); 81 | width: 40px; 82 | display: block; 83 | text-align: center; 84 | } 85 | 86 | footer .color-scheme-toggle label input:checked+span { 87 | color: var(--white-txt-on-blue-bg); 88 | background-color: var(--blue); 89 | } -------------------------------------------------------------------------------- /source/css/giscus.css: -------------------------------------------------------------------------------- 1 | .giscus { 2 | width: calc(100% - 32px); 3 | max-width: 800px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | padding: 0 16px; 7 | } 8 | -------------------------------------------------------------------------------- /source/css/index.css: -------------------------------------------------------------------------------- 1 | .hero { 2 | height: calc(100vh - 56px); 3 | display: grid; 4 | place-items: center; 5 | } 6 | 7 | .hero .group { 8 | width: 100%; 9 | } 10 | 11 | .hero .sub { 12 | text-transform: uppercase; 13 | font-size: 24px; 14 | color: var(--black-4); 15 | font-weight: 100; 16 | margin: 0; 17 | transition: font-size 0.5s; 18 | } 19 | 20 | .hero .large { 21 | font-size: 128px; 22 | color: var(--black-2); 23 | margin: 0; 24 | transition: font-size 0.5s; 25 | } 26 | 27 | @media screen and (max-width: 800px) { 28 | .hero .sub { 29 | font-size: 16px; 30 | } 31 | .hero .large { 32 | font-size: 84px; 33 | } 34 | } -------------------------------------------------------------------------------- /source/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | transition: color 0.2s, background-color 0.2s; 3 | } 4 | 5 | body { 6 | margin: 0; 7 | margin-top: 56px; 8 | color: var(--black-2); 9 | background-color: var(--body-bg); 10 | font-family: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 11 | } 12 | 13 | a:link { 14 | color: var(--link); 15 | text-decoration: none; 16 | } 17 | 18 | a:hover { 19 | text-decoration: underline; 20 | } 21 | 22 | a:active { 23 | text-decoration: none; 24 | } 25 | 26 | a:visited { 27 | color: var(--link); 28 | text-decoration: none; 29 | } 30 | 31 | .container { 32 | max-width: 980px; 33 | margin: auto; 34 | padding: 0 16px; 35 | } 36 | 37 | .section-title { 38 | font-size: 32px; 39 | line-height: 1.125; 40 | font-weight: 700; 41 | letter-spacing: .004em; 42 | margin-bottom: 24px; 43 | color: var(--card-title); 44 | } 45 | 46 | .theme-command { 47 | display: none; 48 | } -------------------------------------------------------------------------------- /source/css/nav.css: -------------------------------------------------------------------------------- 1 | nav { 2 | background-color: var(--nav-bg); 3 | border-bottom: 1px solid var(--border-color); 4 | user-select: none; 5 | position: fixed; 6 | top: 0; 7 | left: 0; 8 | right: 0; 9 | z-index: 1000; 10 | -webkit-backdrop-filter: var(--blur); 11 | backdrop-filter: var(--blur); 12 | transition: height 0.8s cubic-bezier(0.86, 0, 0.07, 1); 13 | } 14 | 15 | nav>.inner { 16 | max-width: 980px; 17 | margin: auto; 18 | padding: 0 16px; 19 | } 20 | 21 | nav>*>* { 22 | display: inline-block; 23 | } 24 | 25 | nav a, nav a:hover, nav a:focus, nav a:active, nav a:link, nav a:visited { 26 | text-decoration: none; 27 | color: var(--black-4); 28 | } 29 | 30 | nav .title { 31 | margin: 0; 32 | font-size: 20px; 33 | font-weight: 500; 34 | line-height: 48px; 35 | color: var(--black-2)!important; 36 | } 37 | 38 | nav .nav-arrow { 39 | display: none; 40 | } 41 | 42 | nav .nav-items { 43 | float: right; 44 | text-align: right; 45 | } 46 | 47 | nav .nav-item { 48 | display: inline-block; 49 | text-align: center; 50 | flex: 1; 51 | font-size: 16px; 52 | height: 48px; 53 | line-height: 48px; 54 | padding: 0 16px; 55 | transition: padding 0.2s, color 0.5s; 56 | } 57 | 58 | nav .nav-item:hover, nav .nav-item:focus { 59 | color: var(--black-2); 60 | } 61 | 62 | @media screen and (max-width: 600px) { 63 | nav .nav-item { 64 | padding: 0 8px; 65 | } 66 | } 67 | 68 | @media screen and (max-width: 400px) { 69 | nav .nav-item { 70 | padding: 0 4px; 71 | } 72 | } 73 | 74 | nav .nav-item-home { 75 | display: none; 76 | } 77 | 78 | nav .nav-item-icon { 79 | width: 32px; 80 | height: 48px; 81 | background-position: center; 82 | background-size: 24px 24px; 83 | background-repeat: no-repeat; 84 | padding: 0; 85 | } 86 | 87 | nav .nav-item-search { 88 | background-size: 16px 16px; 89 | } 90 | 91 | body[data-color-scheme="auto"] nav .nav-item-github, body[data-color-scheme="light"] nav .nav-item-github { 92 | background-image: url(/theme-img/github-mark-dark.png); 93 | } 94 | 95 | body[data-color-scheme="auto"] nav .nav-item-patreon, body[data-color-scheme="light"] nav .nav-item-patreon { 96 | background-image: url(/theme-img/patreon-logo-black.png); 97 | } 98 | 99 | body[data-color-scheme="auto"] nav .nav-item-codepen, body[data-color-scheme="light"] nav .nav-item-codepen { 100 | background-image: url(https://blog.codepen.io/wp-content/uploads/2012/06/Button-Fill-Black-Large.png); 101 | } 102 | 103 | body[data-color-scheme="auto"] nav .nav-item-mastodon, body[data-color-scheme="light"] nav .nav-item-mastodon { 104 | background-image: url(/theme-img/mastodon-logo-black.svg); 105 | } 106 | 107 | body[data-color-scheme="auto"] nav .nav-item-discord, body[data-color-scheme="light"] nav .nav-item-discord { 108 | background-image: url(/theme-img/discord-mark-dark.svg); 109 | } 110 | 111 | body[data-color-scheme="auto"] nav .nav-item-search, body[data-color-scheme="light"] nav .nav-item-search { 112 | background-image: url(/theme-img/search-dark.svg); 113 | } 114 | 115 | @media (prefers-color-scheme: dark) { 116 | body[data-color-scheme="auto"] nav .nav-item-github { 117 | background-image: url(/theme-img/github-mark-light.png); 118 | } 119 | body[data-color-scheme="auto"] nav .nav-item-patreon { 120 | background-image: url(/theme-img/patreon-logo-white.png); 121 | } 122 | body[data-color-scheme="auto"] nav .nav-item-codepen { 123 | background-image: url(https://blog.codepen.io/wp-content/uploads/2012/06/Button-Fill-White-Large.png); 124 | } 125 | body[data-color-scheme="auto"] nav .nav-item-mastodon { 126 | background-image: url(/theme-img/mastodon-logo-white.svg); 127 | } 128 | body[data-color-scheme="auto"] nav .nav-item-discord { 129 | background-image: url(/theme-img/discord-mark-light.svg); 130 | } 131 | body[data-color-scheme="auto"] nav .nav-item-search { 132 | background-image: url(/theme-img/search-light.svg); 133 | } 134 | } 135 | 136 | body[data-color-scheme="dark"] nav .nav-item-github { 137 | background-image: url(/theme-img/github-mark-light.png); 138 | } 139 | 140 | body[data-color-scheme="dark"] nav .nav-item-patreon { 141 | background-image: url(/theme-img/patreon-logo-white.png); 142 | } 143 | 144 | body[data-color-scheme="dark"] nav .nav-item-codepen { 145 | background-image: url(https://blog.codepen.io/wp-content/uploads/2012/06/Button-Fill-White-Large.png); 146 | } 147 | 148 | body[data-color-scheme="dark"] nav .nav-item-mastodon { 149 | background-image: url(/theme-img/mastodon-logo-white.svg); 150 | } 151 | 152 | body[data-color-scheme="dark"] nav .nav-item-discord { 153 | background-image: url(/theme-img/discord-mark-light.svg); 154 | } 155 | 156 | body[data-color-scheme="dark"] nav .nav-item-search { 157 | background-image: url(/theme-img/search-light.svg); 158 | } 159 | 160 | @media screen and (max-width: 600px) { 161 | nav { 162 | height: 48px; 163 | overflow: hidden; 164 | } 165 | nav .title { 166 | pointer-events: none; 167 | display: inline-block; 168 | transition: all 0.2s; 169 | transition-delay: 0.6s; 170 | } 171 | nav .nav-arrow { 172 | display: inline-block; 173 | margin-top: 8px; 174 | width: 40px; 175 | height: 30px; 176 | float: right; 177 | } 178 | nav .nav-arrow::before, nav .nav-arrow::after { 179 | content: ''; 180 | background-color: var(--nav-arrow); 181 | display: block; 182 | position: absolute; 183 | top: 28px; 184 | width: 12px; 185 | height: 1px; 186 | transition: transform 1s cubic-bezier(0.86, 0, 0.07, 1), transform-origin 1s cubic-bezier(0.86, 0, 0.07, 1), top 1s cubic-bezier(0.86, 0, 0.07, 1); 187 | } 188 | nav .nav-arrow::before { 189 | transform-origin: 100% 100%; 190 | transform: rotate(40deg) scaleY(1.5); 191 | right: 50%; 192 | } 193 | nav .nav-arrow::after { 194 | transform-origin: 0% 100%; 195 | transform: rotate(-40deg) scaleY(1.5); 196 | left: 50%; 197 | } 198 | nav .nav-items { 199 | width: 100%; 200 | float: none; 201 | opacity: 0; 202 | transition: all 0.8s cubic-bezier(0.86, 0, 0.07, 1); 203 | transform: translate(0, -20%); 204 | } 205 | nav .nav-item { 206 | pointer-events: none; 207 | display: block; 208 | text-align: left; 209 | } 210 | nav .nav-item-icon { 211 | float: left; 212 | display: inline-block; 213 | } 214 | nav.open .title { 215 | transform: translate(0, 8px); 216 | opacity: 0; 217 | transition-delay: 0s; 218 | } 219 | nav.open .nav-arrow::before, nav.open .nav-arrow::after { 220 | top: 16px; 221 | } 222 | nav.open .nav-arrow::before { 223 | transform-origin: 100% 0%; 224 | transform: rotate(-40deg) scaleY(1.5); 225 | } 226 | nav.open .nav-arrow::after { 227 | transform-origin: 0% 0%; 228 | transform: rotate(40deg) scaleY(1.5); 229 | } 230 | nav.open .nav-item { 231 | pointer-events: initial; 232 | } 233 | nav.open .nav-items { 234 | transform: translate(0, -0%); 235 | opacity: 1; 236 | } 237 | } -------------------------------------------------------------------------------- /source/css/paginator.css: -------------------------------------------------------------------------------- 1 | .paginator { 2 | display: block; 3 | text-align: center; 4 | padding: 16px; 5 | margin: 8px; 6 | } 7 | 8 | .paginator>* { 9 | border-radius: 32px; 10 | padding: 6px 12px; 11 | margin: 0 2px; 12 | user-select: none; 13 | transition: all 0.2s; 14 | } 15 | 16 | .paginator>*:hover { 17 | background-color: var(--card-bg); 18 | } 19 | 20 | .paginator>*:active { 21 | background-color: var(--card-border); 22 | } 23 | 24 | .paginator .current:hover { 25 | background-color: transparent; 26 | } -------------------------------------------------------------------------------- /source/css/post-list.css: -------------------------------------------------------------------------------- 1 | .post-list { 2 | user-select: none; 3 | display: grid; 4 | grid-template-columns: 1fr 1fr; 5 | max-width: 980px; 6 | margin: auto; 7 | } 8 | 9 | @media screen and (max-width: 600px) { 10 | .post-list { 11 | display: block; 12 | max-width: 366px; 13 | } 14 | } 15 | 16 | .post-list-item { 17 | overflow: hidden; 18 | border-radius: 16px; 19 | background-color: var(--card-bg); 20 | margin-bottom: 21px; 21 | transition: all 200ms ease; 22 | } 23 | 24 | .post-list-item:nth-child(2n-1) { 25 | margin-right: 8px; 26 | } 27 | 28 | .post-list-item:nth-child(2n) { 29 | margin-left: 8px; 30 | } 31 | 32 | @media screen and (max-width: 600px) { 33 | .post-list-item:nth-child(n) { 34 | margin-left: 0; 35 | margin-right: 0; 36 | } 37 | } 38 | 39 | .post-list-item .cover-img { 40 | overflow: hidden; 41 | height: 266px; 42 | } 43 | 44 | .post-list-item .cover-img img { 45 | width: 100%; 46 | height: 100%; 47 | object-fit: cover; 48 | filter: brightness(1); 49 | transition: transform 400ms cubic-bezier(0.4, 0, 0.25, 1), 50 | filter 400ms cubic-bezier(0.4, 0, 0.25, 1); 51 | } 52 | 53 | .post-list-item:hover .cover-img img, 54 | .post-list-item > a:focus .cover-img img { 55 | transform: scale(1.03); 56 | filter: brightness(0.85); 57 | } 58 | 59 | .post-list-item .title { 60 | font-size: 24px; 61 | line-height: 1.16667; 62 | font-weight: 700; 63 | letter-spacing: 0.009em; 64 | max-height: 7em; 65 | color: var(--card-title); 66 | overflow: hidden; 67 | } 68 | 69 | .post-list-item .content { 70 | padding: 32px; 71 | } 72 | 73 | .post-list-item a, 74 | .post-list-item a:hover, 75 | .post-list-item a:focus, 76 | .post-list-item a:active, 77 | .post-list-item a:link, 78 | .post-list-item a:visited { 79 | font-weight: bold; 80 | font-size: 24px; 81 | color: var(--black); 82 | text-decoration: none; 83 | } 84 | 85 | .post-list-item .categories { 86 | color: var(--link); 87 | margin-bottom: 6px; 88 | font-weight: 600; 89 | } 90 | 91 | .post-list-item .categories span { 92 | font-size: 11px; 93 | margin-right: 6px; 94 | text-decoration: none; 95 | } 96 | 97 | .post-list-item .excerpt { 98 | font-size: 17px; 99 | color: var(--black-1); 100 | } 101 | 102 | @media screen and (max-width: 800px) { 103 | .post-list-item .content { 104 | font-size: 12px; 105 | } 106 | } 107 | 108 | .post-list-item .time { 109 | font-size: 14px; 110 | line-height: 1.28577; 111 | font-weight: 600; 112 | letter-spacing: -0.016em; 113 | display: flex; 114 | justify-content: flex-start; 115 | align-items: center; 116 | margin-top: 12px; 117 | color: var(--card-time); 118 | } 119 | 120 | .post-list-item .read-more { 121 | text-align: right; 122 | } 123 | 124 | .post-list-item .read-more button { 125 | font-size: 12px; 126 | outline: none; 127 | border: none; 128 | background-color: var(--blue); 129 | color: var(--white-txt-on-blue-bg); 130 | padding: 6px 12px; 131 | border-radius: 32px; 132 | cursor: pointer; 133 | } 134 | 135 | /* in archive page, use a more compact list view */ 136 | 137 | .post-list.archives { 138 | display: block; 139 | max-width: 980px; 140 | margin: auto; 141 | } 142 | 143 | .post-list.archives .post-list-item { 144 | border-radius: 0; 145 | background-color: initial; 146 | padding: 21px 0; 147 | margin: 0; 148 | border-bottom: 1px solid var(--border-color); 149 | transition: all 200ms ease; 150 | } 151 | 152 | .post-list.archives .post-list-item:nth-child(n) { 153 | margin-left: 0; 154 | margin-right: 0; 155 | } 156 | 157 | .post-list.archives .post-list-item:last-child { 158 | border-bottom: none; 159 | } 160 | 161 | .post-list.archives .post-list-item a { 162 | display: flex; 163 | } 164 | 165 | .post-list.archives .post-list-item .cover-img { 166 | height: initial; 167 | min-width: 180px; 168 | width: 20vw; 169 | border-radius: 16px; 170 | flex-shrink: 0; 171 | } 172 | -------------------------------------------------------------------------------- /source/css/post.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: var(--body-bg); 3 | } 4 | 5 | .post { 6 | margin: 128px 0; 7 | } 8 | 9 | .meta .categories { 10 | color: var(--link); 11 | margin-bottom: 6px; 12 | font-weight: 600; 13 | } 14 | 15 | .meta .categories a { 16 | font-size: 13px; 17 | margin-right: 6px; 18 | text-decoration: none; 19 | } 20 | 21 | .meta .date { 22 | color: var(--grey); 23 | font-weight: 600; 24 | } 25 | 26 | .meta .title { 27 | font-size: 48px; 28 | margin-top: 16px; 29 | } 30 | 31 | .content { 32 | font-size: 19px; 33 | line-height: 1.4211; 34 | font-weight: 400; 35 | letter-spacing: 0.012em; 36 | } 37 | 38 | .content p, 39 | .content h1, 40 | .content h2, 41 | .content h3, 42 | .content h4, 43 | .content h5, 44 | .content h6, 45 | .meta .categories, 46 | .meta .date, 47 | .content figure, 48 | /* only `.content>pre`, do not include
 in 
*/ 49 | .content>pre, 50 | .divider, 51 | .container, 52 | hr, 53 | .meta .title, 54 | .toc, 55 | .content blockquote, 56 | .content table, 57 | .content video, 58 | .content ul, 59 | .content ol, 60 | .content > mjx-container, 61 | .content > .katex, 62 | .about { 63 | max-width: 800px; 64 | margin-left: auto; 65 | margin-right: auto; 66 | padding: 0 16px; 67 | } 68 | 69 | .content p img, 70 | .content .block-large img { 71 | border-radius: 10px; 72 | } 73 | 74 | .content table, 75 | .content video { 76 | display: block; 77 | } 78 | 79 | .content table { 80 | padding: 0; 81 | border-collapse: collapse; 82 | border-radius: 15px; 83 | max-width: 800px; 84 | overflow-x: auto; 85 | } 86 | 87 | .content table tr { 88 | background-color: var(--card-bg); 89 | } 90 | 91 | .content table tr:nth-child(even) { 92 | background-color: transparent; 93 | } 94 | 95 | .content table th, 96 | .content table td { 97 | margin: 0; 98 | padding: 6px 12px; 99 | } 100 | 101 | .content table th { 102 | border-bottom: 1px solid var(--border-color); 103 | } 104 | 105 | .content table thead tr th:first-child { 106 | border-top-left-radius: 15px; 107 | } 108 | 109 | .content table thead tr th:last-child { 110 | border-top-right-radius: 15px; 111 | } 112 | 113 | .content table tbody tr:last-child td:first-child { 114 | border-bottom-left-radius: 15px; 115 | } 116 | 117 | .content table tbody tr:last-child td:last-child { 118 | border-bottom-right-radius: 15px; 119 | } 120 | 121 | @media screen and (max-width: 800px) { 122 | .content table, 123 | .content table thead tr th:first-child, 124 | .content table thead tr th:last-child, 125 | .content table tbody tr:last-child td:first-child, 126 | .content table tbody tr:last-child td:last-child { 127 | border-radius: 0; 128 | } 129 | } 130 | 131 | .content video { 132 | max-width: 100%; 133 | padding: 0; 134 | } 135 | 136 | .content .highlight, 137 | .content > pre { 138 | overflow-x: auto; 139 | overflow-y: hidden; 140 | background-color: var(--card-bg); 141 | border-radius: 15px; 142 | max-width: calc(800px - 16px * 2); 143 | } 144 | 145 | @media screen and (max-width: 800px) { 146 | .content .highlight, 147 | .content > pre { 148 | border-radius: 0; 149 | } 150 | } 151 | 152 | .content .highlight * { 153 | border: none; 154 | } 155 | 156 | .content .highlight .gutter { 157 | padding-right: 16px; 158 | } 159 | 160 | .content > pre { 161 | max-width: calc(800px - 24px * 2); 162 | padding: 20px 24px; 163 | } 164 | 165 | .content > pre > code { 166 | background-color: transparent; 167 | } 168 | 169 | .content ul, 170 | .content ol { 171 | padding: 0 16px; 172 | padding-left: 32px; 173 | margin-block-start: 1em; 174 | margin-block-end: 1em; 175 | max-width: calc(800px - 16px * 2); 176 | } 177 | 178 | .content blockquote { 179 | max-width: calc(800px - 16px * 2); 180 | padding: 0 8px; 181 | } 182 | 183 | /* for [hexo-math](https://github.com/hexojs/hexo-math): */ 184 | .content > mjx-container, 185 | .content > .katex { 186 | display: block; 187 | text-align: center; 188 | } 189 | 190 | .tags { 191 | display: flex; 192 | flex-wrap: wrap; 193 | } 194 | 195 | .tags .icon { 196 | --size: 14px; 197 | background-position: center; 198 | background-size: var(--size) var(--size); 199 | background-repeat: no-repeat; 200 | display: block; 201 | width: var(--size); 202 | height: var(--size); 203 | margin-right: 6px; 204 | } 205 | 206 | body[data-color-scheme="auto"] .tags .icon { 207 | background-image: url(/theme-img/tags-dark.svg); 208 | } 209 | 210 | @media (prefers-color-scheme: dark) { 211 | body[data-color-scheme="auto"] .tags .icon { 212 | background-image: url(/theme-img/tags-light.svg); 213 | } 214 | } 215 | 216 | body[data-color-scheme="dark"] .tags .icon { 217 | background-image: url(/theme-img/tags-light.svg); 218 | } 219 | 220 | .tags .tag { 221 | font-size: 14px; 222 | display: block; 223 | height: 14px; 224 | margin-right: 4px; 225 | } 226 | 227 | .about { 228 | border-radius: 7px; 229 | background-color: var(--card-bg); 230 | max-width: calc(800px - 16px * 2); 231 | padding: 16px; 232 | margin: 64px auto; 233 | } 234 | 235 | @media screen and (max-width: 800px) { 236 | .about { 237 | border-radius: 0; 238 | } 239 | } 240 | 241 | .about h1 { 242 | margin: 0; 243 | } 244 | 245 | .about .details { 246 | margin: 16px 0; 247 | } 248 | 249 | .about .details p { 250 | margin: 6px 0; 251 | } 252 | 253 | .content h1 > .headerlink, 254 | .content h2 > .headerlink, 255 | .content h3 > .headerlink, 256 | .content h4 > .headerlink, 257 | .content h5 > .headerlink, 258 | .content h6 > .headerlink { 259 | opacity: 0; 260 | color: var(--grey); 261 | font-weight: normal; 262 | position: absolute; 263 | padding-right: 6px; 264 | transform: translateX(-100%); 265 | transition: opacity 0.2s; 266 | } 267 | 268 | .content h1:hover > .headerlink, 269 | .content h2:hover > .headerlink, 270 | .content h3:hover > .headerlink, 271 | .content h4:hover > .headerlink, 272 | .content h5:hover > .headerlink, 273 | .content h6:hover > .headerlink { 274 | opacity: 1; 275 | text-decoration: none; 276 | } 277 | 278 | .content h1 > .headerlink::before, 279 | .content h2 > .headerlink::before, 280 | .content h3 > .headerlink::before, 281 | .content h4 > .headerlink::before, 282 | .content h5 > .headerlink::before, 283 | .content h6 > .headerlink::before { 284 | content: "#"; 285 | } 286 | 287 | .content > h1 { 288 | font-size: 36px; 289 | } 290 | 291 | .content > h2 { 292 | font-size: 30px; 293 | } 294 | 295 | .content > h3 { 296 | font-size: 26px; 297 | } 298 | 299 | .content > h4 { 300 | font-size: 20px; 301 | } 302 | 303 | .content > h5 { 304 | font-size: 16px; 305 | } 306 | 307 | .content > h6 { 308 | font-size: 14px; 309 | } 310 | 311 | .post-prev-next { 312 | display: flex; 313 | justify-content: space-between; 314 | } 315 | 316 | .post-prev-next > a { 317 | width: 50%; 318 | color: var(--black-4); 319 | text-decoration: none; 320 | } 321 | 322 | .post-prev-next > a:hover { 323 | color: var(--black-2); 324 | } 325 | 326 | .post-prev-next > a > div { 327 | display: flex; 328 | } 329 | 330 | .post-prev-next .text { 331 | display: flex; 332 | flex-direction: column; 333 | } 334 | 335 | .post-prev-next .prev > div { 336 | justify-content: flex-end; 337 | text-align: right; 338 | } 339 | 340 | .post-prev-next .prev .text { 341 | align-items: flex-end; 342 | } 343 | 344 | .post-prev-next .text * { 345 | margin: 0; 346 | } 347 | 348 | .post-prev-next .text .label { 349 | margin-bottom: 4px; 350 | color: var(--grey); 351 | } 352 | -------------------------------------------------------------------------------- /source/css/rainbow-banner.css: -------------------------------------------------------------------------------- 1 | .rainbow-banner { 2 | background-image: var(--gradient); 3 | height: 6px; 4 | position: fixed; 5 | top: 0; 6 | left: 0; 7 | right: 0; 8 | z-index: 900; 9 | } 10 | -------------------------------------------------------------------------------- /source/css/search.css: -------------------------------------------------------------------------------- 1 | #searchbox { 2 | display: block; 3 | outline: none; 4 | width: calc(100% - 16px * 2); 5 | background-color: var(--white); 6 | color: var(--black-2); 7 | border: 1px solid var(--border-color); 8 | padding: 12px 16px; 9 | font-size: 20px; 10 | border-radius: 12px; 11 | } 12 | 13 | #searchbox:hover, 14 | #searchbox:focus-visible { 15 | background-color: var(--white-1); 16 | color: var(--black); 17 | } 18 | 19 | #searchbox::placeholder { 20 | color: var(--grey); 21 | } 22 | 23 | #search-results { 24 | margin-bottom: 128px; 25 | } 26 | 27 | #search-results .no-results { 28 | color: var(--grey); 29 | text-align: center; 30 | } 31 | -------------------------------------------------------------------------------- /source/css/tags.css: -------------------------------------------------------------------------------- 1 | .tags .tag { 2 | padding: 8px 16px; 3 | margin: 4px; 4 | font-size: 14px; 5 | border-radius: 980px; 6 | background-color: var(--white); 7 | color: var(--black-2); 8 | text-decoration: none; 9 | border: 1px solid var(--border-color); 10 | } 11 | 12 | .tags .tag:hover { 13 | background-color: var(--white-1); 14 | color: var(--black); 15 | } 16 | 17 | .tags { 18 | margin-bottom: 128px; 19 | } 20 | -------------------------------------------------------------------------------- /source/css/toc.css: -------------------------------------------------------------------------------- 1 | .toc > p { 2 | margin: 0; 3 | } 4 | 5 | .toc > p > a { 6 | color: var(--black-4); 7 | text-decoration: none; 8 | display: inline-block; 9 | padding: 8px 0; 10 | padding-left: 12px; 11 | border-left: 1px solid var(--border-color); 12 | transition: color 0.2s, border-color 0.2s; 13 | } 14 | 15 | .toc > p > a:hover, 16 | .toc > p > a:focus-visible { 17 | color: var(--black); 18 | text-decoration: none; 19 | border-color: var(--black-2); 20 | } 21 | -------------------------------------------------------------------------------- /source/css/typography.css: -------------------------------------------------------------------------------- 1 | .divider, hr { 2 | border: none; 3 | border-top: 1px solid var(--white-1); 4 | margin: 32px auto; 5 | } 6 | 7 | .divider { 8 | margin: 64px auto; 9 | } 10 | 11 | img { 12 | width: 100%; 13 | } 14 | 15 | ::marker { 16 | color: var(--black-4); 17 | } 18 | 19 | blockquote { 20 | border-left: 4px solid var(--white-2); 21 | } 22 | 23 | pre, code { 24 | font-family: 'JetBrains Mono', 'Courier New', Courier, monospace; 25 | } 26 | 27 | pre { 28 | font-size: 14px; 29 | } 30 | 31 | code { 32 | font-size: 12px; 33 | background-color: var(--white-1); 34 | padding: 2px 4px; 35 | border-radius: 4px; 36 | } -------------------------------------------------------------------------------- /source/css/var.css: -------------------------------------------------------------------------------- 1 | body[data-color-scheme="auto"], body[data-color-scheme="light"] { 2 | --white-opacity-8: rgba(255, 255, 255, .8); 3 | --white-1-opacity-8: rgba(229.5, 229.5, 229.5, .8); 4 | --white: #fff; 5 | --white-1: rgb(229.5, 229.5, 229.5); 6 | --white-2: rgb(204, 204, 204); 7 | 8 | --grey: rgb(127.5, 127.5, 127.5); 9 | 10 | --black: #000; 11 | --black-2: rgb(51, 51, 51); 12 | --black-4: rgb(102, 102, 102); 13 | 14 | --border-color: #8882; 15 | 16 | --link: #06c; 17 | 18 | --blur: blur(32px); 19 | 20 | --blue: #0071e3; 21 | --white-txt-on-blue-bg: #fff; 22 | 23 | --nav-bg: var(--white-opacity-8); 24 | 25 | --footer-link-grey: #515154; 26 | 27 | --body-bg: #fbfbfd; 28 | --card-bg: #fff; 29 | --card-title: #1d1d1f; 30 | --card-time: #6e6e73; 31 | --date-txt: #6e6e73; 32 | 33 | --nav-arrow: #1d1d1f; 34 | } 35 | 36 | @media (prefers-color-scheme: dark) { 37 | body[data-color-scheme="auto"] { 38 | --white-opacity-8: rgba(0, 0, 0, .8); 39 | --white-1-opacity-8: rgba(25.5, 25.5, 25.5, .8); 40 | --white: #000; 41 | --white-1: rgb(25.5, 25.5, 25.5); 42 | --white-2: rgb(51, 51, 51); 43 | 44 | --black: #fff; 45 | --black-2: rgb(204, 204, 204); 46 | --black-4: rgb(153, 153, 153); 47 | 48 | --border-color: #8884; 49 | 50 | --link: #5fafff; 51 | 52 | --blur: blur(32px); 53 | 54 | --blue: #00376f; 55 | --white-txt-on-blue-bg: #c0dfff; 56 | 57 | --nav-bg: rgba(0, 0, 0, .5); 58 | 59 | --footer-link-grey: #a1a1a6; 60 | 61 | --body-bg: #101010; 62 | --card-bg: #181818; 63 | --card-title: #cfcfd5; 64 | --card-time: #6e6e73; 65 | --date-txt: #6e6e73; 66 | 67 | --nav-arrow: #e5e5ee; 68 | } 69 | } 70 | 71 | body[data-color-scheme="dark"] { 72 | --white-opacity-8: rgba(0, 0, 0, .8); 73 | --white-1-opacity-8: rgba(25.5, 25.5, 25.5, .8); 74 | --white: #000; 75 | --white-1: rgb(25.5, 25.5, 25.5); 76 | --white-2: rgb(51, 51, 51); 77 | 78 | --black: #fff; 79 | --black-2: rgb(204, 204, 204); 80 | --black-4: rgb(153, 153, 153); 81 | 82 | --border-color: #8884; 83 | 84 | --link: #5fafff; 85 | 86 | --blur: blur(32px); 87 | 88 | --blue: #00376f; 89 | --white-txt-on-blue-bg: #c0dfff; 90 | 91 | --nav-bg: rgba(0, 0, 0, .5); 92 | 93 | --footer-link-grey: #a1a1a6; 94 | 95 | --body-bg: #101010; 96 | --card-bg: #181818; 97 | --card-title: #cfcfd5; 98 | --card-time: #6e6e73; 99 | --date-txt: #6e6e73; 100 | 101 | --nav-arrow: #e5e5ee; 102 | } 103 | -------------------------------------------------------------------------------- /source/js/main.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | var navEl = document.getElementById('theme-nav'); 3 | navEl.addEventListener('click', (e) => { 4 | if (window.innerWidth <= 600) { 5 | if (navEl.classList.contains('open')) { 6 | navEl.style.height = '' 7 | } else { 8 | navEl.style.height = 48 + document.querySelector('#theme-nav .nav-items').clientHeight + 'px' 9 | } 10 | navEl.classList.toggle('open') 11 | } else { 12 | if (navEl.classList.contains('open')) { 13 | navEl.style.height = '' 14 | navEl.classList.remove('open') 15 | } 16 | } 17 | }) 18 | window.addEventListener('resize', (e) => { 19 | if (navEl.classList.contains('open')) { 20 | navEl.style.height = 48 + document.querySelector('#theme-nav .nav-items').clientHeight + 'px' 21 | } 22 | if (window.innerWidth > 600) { 23 | if (navEl.classList.contains('open')) { 24 | navEl.style.height = '' 25 | navEl.classList.remove('open') 26 | } 27 | } 28 | }) 29 | 30 | // a simple solution for managing cookies 31 | const Cookies = new class { 32 | get(key, fallback) { 33 | const temp = document.cookie.split('; ').find(row => row.startsWith(key + '=')) 34 | if (temp) { 35 | return temp.split('=')[1]; 36 | } else { 37 | return fallback 38 | } 39 | } 40 | set(key, value) { 41 | document.cookie = key + '=' + value + '; path=' + document.body.getAttribute('data-config-root') 42 | } 43 | } 44 | 45 | const ColorScheme = new class { 46 | constructor() { 47 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { this.updateCurrent(Cookies.get('color-scheme', 'auto')) }) 48 | } 49 | get() { 50 | const stored = Cookies.get('color-scheme', 'auto') 51 | this.updateCurrent(stored) 52 | return stored 53 | } 54 | set(value) { 55 | bodyEl.setAttribute('data-color-scheme', value) 56 | Cookies.set('color-scheme', value) 57 | this.updateCurrent(value) 58 | return value 59 | } 60 | updateCurrent(value) { 61 | var current = 'light' 62 | if (value == 'auto') { 63 | if (window.matchMedia('(prefers-color-scheme: dark)').matches) { 64 | current = 'dark' 65 | } 66 | } else { 67 | current = value 68 | } 69 | document.body.setAttribute('data-current-color-scheme', current) 70 | } 71 | } 72 | 73 | if (document.getElementById('theme-color-scheme-toggle')) { 74 | var bodyEl = document.body 75 | var themeColorSchemeToggleEl = document.getElementById('theme-color-scheme-toggle') 76 | var options = themeColorSchemeToggleEl.getElementsByTagName('input') 77 | 78 | if (ColorScheme.get()) { 79 | bodyEl.setAttribute('data-color-scheme', ColorScheme.get()) 80 | } 81 | 82 | for (const option of options) { 83 | if (option.value == bodyEl.getAttribute('data-color-scheme')) { 84 | option.checked = true 85 | } 86 | option.addEventListener('change', (ev) => { 87 | var value = ev.target.value 88 | ColorScheme.set(value) 89 | for (const o of options) { 90 | if (o.value != value) { 91 | o.checked = false 92 | } 93 | } 94 | }) 95 | } 96 | } 97 | 98 | if (document.body.attributes['data-rainbow-banner']) { 99 | var shown = false 100 | switch (document.body.attributes['data-rainbow-banner-shown'].value) { 101 | case 'always': 102 | shown = true 103 | break; 104 | case 'auto': 105 | shown = new Date().getMonth() + 1 == parseInt(document.body.attributes['data-rainbow-banner-month'].value, 10) 106 | break; 107 | default: 108 | break; 109 | } 110 | if (shown) { 111 | var banner = document.createElement('div') 112 | 113 | banner.style.setProperty('--gradient', `linear-gradient(90deg, ${document.body.attributes['data-rainbow-banner-colors'].value})`) 114 | banner.classList.add('rainbow-banner') 115 | 116 | navEl.after(banner) 117 | } 118 | } 119 | 120 | if (document.body.attributes['data-toc']) { 121 | const content = document.getElementsByClassName('content')[0] 122 | const maxDepth = document.body.attributes['data-toc-max-depth'].value 123 | 124 | var headingSelector = '' 125 | for (var i = 1; i <= maxDepth; i++) { 126 | headingSelector += 'h' + i + ',' 127 | } 128 | headingSelector = headingSelector.slice(0, -1) 129 | const headings = content.querySelectorAll(headingSelector) 130 | 131 | var source = [] 132 | headings.forEach((heading) => { 133 | source.push({ 134 | html: heading.innerHTML, 135 | href: heading.getElementsByClassName('headerlink')[0].attributes['href'].value 136 | }) 137 | }) 138 | 139 | const toc = document.createElement('div') 140 | toc.classList.add('toc') 141 | for (const i in source) { 142 | const item = document.createElement('p') 143 | const link = document.createElement('a') 144 | link.href = source[i].href 145 | link.innerHTML = source[i].html 146 | link.removeChild(link.getElementsByClassName('headerlink')[0]) 147 | item.appendChild(link) 148 | toc.appendChild(item) 149 | } 150 | 151 | if (toc.children.length != 0) { 152 | document.getElementsByClassName('post')[0].getElementsByClassName('divider')[0].after(toc) 153 | const divider = document.createElement('div') 154 | divider.classList.add('divider') 155 | toc.after(divider) 156 | } 157 | } 158 | })() -------------------------------------------------------------------------------- /source/js/search.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | var searchIndex = [] 3 | const searchForm = document.getElementById('search-form') 4 | const searchBox = document.getElementById('searchbox') 5 | const searchResults = document.getElementById('search-results') 6 | 7 | searchBox.select() 8 | 9 | const doSearch = (keyword) => { 10 | var results = [] 11 | var resultsEl = [] 12 | 13 | for (let i = 0; i < searchIndex.length; i++) { 14 | const currentItem = searchIndex[i]; 15 | 16 | if (JSON.stringify(currentItem).search(keyword) !== -1) { 17 | results.push(currentItem) 18 | } 19 | } 20 | 21 | if (results.length > 0) { 22 | for (let i = 0; i < results.length; i++) { 23 | const currentResult = results[i]; 24 | const currentResultEl = document.createElement('article') 25 | currentResultEl.classList.add('post-list-item') 26 | currentResultEl.innerHTML = ` 27 | 28 |
29 | ${(() => { 30 | if (currentResult.categories) { 31 | return `
${(() => { 32 | let categories = '' 33 | for (let i = 0; i < currentResult.categories.length; i++) { 34 | const currentCategory = currentResult.categories[i] 35 | categories += `${currentCategory}` 36 | } 37 | return categories 38 | })()}
` 39 | } else { 40 | return '' 41 | } 42 | })()} 43 |
${currentResult.title}
44 |
45 |
46 | ` 47 | resultsEl.push(currentResultEl) 48 | } 49 | } else { 50 | const el = document.createElement('div') 51 | el.className = 'no-results' 52 | el.innerHTML = 'No results found.' 53 | resultsEl.push(el) 54 | } 55 | 56 | searchResults.innerHTML = '' 57 | for (let i = 0; i < resultsEl.length; i++) { 58 | const element = resultsEl[i]; 59 | searchResults.appendChild(element) 60 | } 61 | } 62 | 63 | searchForm.addEventListener('submit', (ev) => { 64 | ev.preventDefault() 65 | if (searchIndex != '') { 66 | doSearch(searchBox.value) 67 | } else { 68 | fetch(document.body.attributes['data-config-root'].value + document.body.attributes['data-search-path'].value).then(res => res.json()).then(data => { 69 | searchIndex = data 70 | doSearch(searchBox.value) 71 | }) 72 | } 73 | }) 74 | })() -------------------------------------------------------------------------------- /source/js/tidio.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | const f = () => { 3 | try { 4 | document.getElementById( 5 | "tidio-chat-iframe" 6 | ).contentDocument.documentElement.style.colorScheme = "light dark"; 7 | } catch (error) {} 8 | 9 | if ( 10 | document.getElementById("tidio-chat-iframe")?.contentDocument 11 | ?.documentElement?.style?.colorScheme !== "light dark" 12 | ) { 13 | setTimeout(f, 250); 14 | } 15 | }; 16 | 17 | f(); 18 | })(); 19 | -------------------------------------------------------------------------------- /source/theme-img/discord-mark-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/theme-img/discord-mark-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/theme-img/github-mark-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/source/theme-img/github-mark-dark.png -------------------------------------------------------------------------------- /source/theme-img/github-mark-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/source/theme-img/github-mark-light.png -------------------------------------------------------------------------------- /source/theme-img/mastodon-logo-black.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/theme-img/mastodon-logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/theme-img/patreon-logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/source/theme-img/patreon-logo-black.png -------------------------------------------------------------------------------- /source/theme-img/patreon-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrWillCom/hexo-theme-cupertino/7bd237996a154bda3f6bdac5384042fbeb83cbc0/source/theme-img/patreon-logo-white.png -------------------------------------------------------------------------------- /source/theme-img/search-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /source/theme-img/search-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /source/theme-img/tags-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/theme-img/tags-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | --------------------------------------------------------------------------------