Full Code of ppoffice/hexo-theme-icarus for AI

master 76d8cd019700 cached
122 files
183.3 KB
49.3k tokens
76 symbols
1 requests
Download .txt
Showing preview only (207K chars total). Download the full file or copy to clipboard to get everything.
Repository: ppoffice/hexo-theme-icarus
Branch: master
Commit: 76d8cd019700
Files: 122
Total size: 183.3 KB

Directory structure:
gitextract_bspt8wyp/

├── .eslintignore
├── .eslintrc.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug反馈.md
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   ├── feature_request.md
│   │   └── 功能建议.md
│   ├── PULL_REQUEST_TEMPLATE/
│   │   └── pull_request_template.md
│   ├── dependabot.yml
│   ├── stale.yml
│   └── workflows/
│       ├── github-release.yml
│       ├── lint.yml
│       ├── npm-publish.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── include/
│   ├── config.js
│   ├── dependency.js
│   ├── migration/
│   │   ├── head.js
│   │   ├── v2_v3.js
│   │   ├── v3_v4.js
│   │   ├── v4_v5.js
│   │   └── v5_v5.1.js
│   ├── register.js
│   ├── schema/
│   │   ├── comment/
│   │   │   └── .gitkeep
│   │   ├── common/
│   │   │   ├── article.json
│   │   │   ├── comment.json
│   │   │   ├── donates.json
│   │   │   ├── footer.json
│   │   │   ├── head.json
│   │   │   ├── navbar.json
│   │   │   ├── plugins.json
│   │   │   ├── providers.json
│   │   │   ├── search.json
│   │   │   ├── share.json
│   │   │   ├── sidebar.json
│   │   │   └── widgets.json
│   │   ├── config.json
│   │   ├── donate/
│   │   │   └── .gitkeep
│   │   ├── misc/
│   │   │   └── .gitkeep
│   │   ├── plugin/
│   │   │   ├── animejs.json
│   │   │   ├── back_to_top.json
│   │   │   └── pjax.json
│   │   ├── search/
│   │   │   └── .gitkeep
│   │   ├── share/
│   │   │   └── .gitkeep
│   │   └── widget/
│   │       └── profile.json
│   ├── style/
│   │   ├── article.styl
│   │   ├── base.styl
│   │   ├── button.styl
│   │   ├── card.styl
│   │   ├── codeblock.styl
│   │   ├── donate.styl
│   │   ├── footer.styl
│   │   ├── helper.styl
│   │   ├── navbar.styl
│   │   ├── pagination.styl
│   │   ├── plugin.styl
│   │   ├── responsive.styl
│   │   ├── search.styl
│   │   ├── timeline.styl
│   │   └── widget.styl
│   └── util/
│       └── console.js
├── languages/
│   ├── de.yml
│   ├── en.yml
│   ├── es.yml
│   ├── fr.yml
│   ├── id.yml
│   ├── it.yml
│   ├── ja.yml
│   ├── ko.yml
│   ├── pl.yml
│   ├── pt-BR.yml
│   ├── ru.yml
│   ├── sv.yml
│   ├── tk.yml
│   ├── tr.yml
│   ├── vn.yml
│   ├── zh-CN.yml
│   └── zh-TW.yml
├── layout/
│   ├── archive.jsx
│   ├── categories.jsx
│   ├── category.jsx
│   ├── comment/
│   │   └── .gitkeep
│   ├── common/
│   │   ├── article.jsx
│   │   ├── comment.jsx
│   │   ├── donates.jsx
│   │   ├── footer.jsx
│   │   ├── head.jsx
│   │   ├── navbar.jsx
│   │   ├── plugins.jsx
│   │   ├── scripts.jsx
│   │   ├── search.jsx
│   │   ├── share.jsx
│   │   └── widgets.jsx
│   ├── donate/
│   │   └── .gitkeep
│   ├── index.jsx
│   ├── layout.jsx
│   ├── misc/
│   │   └── .gitkeep
│   ├── page.jsx
│   ├── plugin/
│   │   ├── animejs.jsx
│   │   ├── back_to_top.jsx
│   │   └── pjax.jsx
│   ├── post.jsx
│   ├── search/
│   │   └── .gitkeep
│   ├── share/
│   │   └── .gitkeep
│   ├── tag.jsx
│   ├── tags.jsx
│   └── widget/
│       └── profile.jsx
├── package.json
├── scripts/
│   └── index.js
└── source/
    ├── css/
    │   ├── cyberpunk.styl
    │   ├── default.styl
    │   └── style.styl
    └── js/
        ├── .eslintrc.json
        ├── animation.js
        ├── back_to_top.js
        ├── column.js
        ├── main.js
        └── pjax.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================
node_modules/

================================================
FILE: .eslintrc.json
================================================
{
  "extends": [
    "hexo",
    "plugin:react/recommended",
    "plugin:json/recommended"
  ],
  "settings": {
    "node": {
      "tryExtensions": [
        ".js",
        ".jsx",
        ".json"
      ]
    },
    "react": {
      "version": "16.0"
    }
  },
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "sourceType": "module",
    "ecmaVersion": "latest"
  },
  "plugins": [
    "react"
  ],
  "rules": {
    "react/jsx-uses-vars": "error",
    "indent": [
      "error",
      4,
      {
        "SwitchCase": 1
      }
    ],
    "react/no-unknown-property": [
      "error",
      {
        "ignore": [
          "class",
          "onclick",
          "onload",
          "onsubmit",
          "crossorigin"
        ]
      }
    ],
    "react/react-in-jsx-scope": [
      "off"
    ],
    "react/prop-types": [
      "off"
    ],
    "react/display-name": [
      "off"
    ],
    "react/jsx-key": [
      "off"
    ],
    "react/jsx-no-target-blank": [
      "error",
      {
        "allowReferrer": true
      }
    ]
  }
}

================================================
FILE: .github/ISSUE_TEMPLATE/Bug反馈.md
================================================
---
name: Bug反馈
about: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。
title: [Bug] 问题概述
labels: ''
assignees: ''

---

> 确保你在提交Bug反馈之前仔细阅读了[Hexo文档](https://hexo.io/zh-cn/),[Icarus用户指南](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97/),和[GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues)来了解你的问题是否已经被他人提出过。

**Bug描述**
简洁清晰地描述你遇到的Bug是什么。

**系统与环境**
列出你的Hexo和Icarus的版本和配置。

- Hexo,操作系统,和Node.js的版本(使用`hexo version`命令来查看)
- 站点配置文件`_config.yml`
- 主题配置文件`_config.icarus.yml`或`themes/icarus/_config.yml`
- 其他额外的配置文件(文章front-matter,`_config.post.yml`,或`_config.page.yml`)
- 浏览器版本(如Firefox 70.0,Chrome Android 80.0)

**复现方式**
列出复现这个Bug的步骤,如:

1. 访问‘...’
2. 点击’...‘
3. 下拉到‘...’
4. 出现‘...’的错误

**期望行为**
简洁清晰地描述没有这个情况下你期望得到的结果。

**截图**
如果可以的话,请附上几张截图来帮助说明你遇到的问题。

**额外上下文**
附上与问题有关的其他上下文信息。


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Please follow this template if you are reporting a bug, or your issue may be closed without further notice.
title: [Bug] Bug summary
labels: ''
assignees: ''

---

> Make sure you go through the [Hexo docs](https://hexo.io), [Icarus user manual](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus-User-Guide/), and [GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues) to see if the bug you are reporting has been already addressed by others.

**Describe the bug**
A clear and concise description of what the bug is.

**System and Environment**
The version and configuration of Hexo and Icarus.

- Hexo, OS, and node version (use `hexo version` command to view these information)
- Site configuration file `_config.yml`
- Theme configuration file `_config.icarus.yml` or `themes/icarus/_config.yml`
- Any additional theme configuration files (post front-matter, `_config.post.yml`, or `_config.page.yml`)
- Browser and version (e.g., Firefox 70.0, Chrome Android 80.0)

**To Reproduce**
Steps to reproduce the behavior, such as:

1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. '...' error appears

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: GitHub Discussions
    url: https://github.com/ppoffice/hexo-theme-icarus/discussions
    about: Redirect your Icarus usage questions to here.
  - name: GitHub讨论组
    url: https://github.com/ppoffice/hexo-theme-icarus/discussions
    about: 与Icarus使用相关的问题请转至这里。
  - name: Bug Report
    url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=bug_report.md
    about: Please follow this template if you are reporting a bug, or your issue may be closed without further notice.
  - name: Bug反馈
    url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=Bug反馈.md
    about: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。
  - name: Feature Request
    url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=feature_request.md
    about: Please follow this template if you are requesting a new feature, or your issue may be closed without further notice.
  - name: 功能建议
    url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=功能建议.md
    about: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature Request
about: Please follow this template if you are requesting a new feature, or your issue may be closed without further notice.
title: [FEAT] Feature request summary
labels: ''
assignees: ''

---

> Make sure you go through the [Hexo docs](https://hexo.io), [Icarus user manual](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus-User-Guide/), and [GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues) to see if the feature you are requesting has been already addressed by others.

**Is your feature request related to a problem? Please describe.**

A clear and concise description of what the problem is (e.g., I'm always frustrated when [...]).

**Describe the solution you'd like**

A clear and concise description of what you want to happen.

**Describe alternatives you've considered**

A clear and concise description of any alternative solutions or features you've considered.

**Additional context**

Add any other context or screenshots about the feature request here.


================================================
FILE: .github/ISSUE_TEMPLATE/功能建议.md
================================================
---
name: 功能建议
about: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。
title: [FEAT] 功能建议概述
labels: ''
assignees: ''

---

> 确保你在提交功能建议之前仔细阅读了[Hexo文档](https://hexo.io/zh-cn/),[Icarus用户指南](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97/),和[GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues)来了解你的建议是否已经被他人提出过。

**你的功能建议与某个使用问题相关么?请详述。**

简洁清晰地描述你遇到的问题是什么(如:我在使用...的时候遇到了...)。

**描述你想要的解决方案**

简洁清晰地描述你想要的解决方案可以达到的效果。

**描述你考虑过的替代办法**

简洁清晰地描述你考虑过的替代解决方案或是新功能。

**额外上下文**

附上与功能请求有关的其他上下文信息或者截图。


================================================
FILE: .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
================================================
---
name: Pull Request
about: Suggest a code change to this project.
title: ''
labels: ''
assignees: ''

---

**Note 0**
Please review [the contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) before making this pull request.

**Note 1**

Please break up your pull request into multiple smaller requests if it contains multiple bug fixes 
or new features.
Each pull request should have one bug fix or new feature only for better code maintainability.

**Note 2**

Many components of this theme, including core functions, some Hexo extensions, widgets and plugins, 
have been moved to [ppoffice/hexo-component-inferno](https://github.com/ppoffice/hexo-component-inferno).
Please make a pull request to that repository instead of this one if your changes are related to
the above components.

**Detailed description**

> Please use the [Icarus issue template](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) if it is a bug fix.

> Please use the [Icarus feature request template](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) if it is a bug fix.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: 'npm'
    directory: '/'
    schedule:
      interval: 'daily'


================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 14
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
  - bug:core
  - bug:extension
  - bug:general
  - feature:core
  - feature:extension
  - feature:general
  - tutorial:v1
  - tutorial:v2
  - tutorial:v3
  - tutorial:v4
  - tutorial:v5
  - tutorial:v6
  - tutorial:v7
  - tutorial:v8
  - tutorial:v9
  - Gitalk
  - utterances
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
  This issue has been automatically marked as stale because it has not had
  recent activity. It will be closed if no further activity occurs. Thank you
  for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

================================================
FILE: .github/workflows/github-release.yml
================================================
name: GitHub Release

on:
  push:
    tags:
      - '*'

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v3
      - uses: ncipollo/release-action@v1
        with:
          tag: ${{ github.ref }}
          name: ${{ github.ref }}
          draft: true
          prerelease: false


================================================
FILE: .github/workflows/lint.yml
================================================
name: Code Linting

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: latest
      - run: npm install
      - run: npm run lint


================================================
FILE: .github/workflows/npm-publish.yml
================================================
name: Node.js Package

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 14
          registry-url: https://registry.npmjs.org/
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}


================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [14, latest]
      fail-fast: false
    steps:
      - uses: actions/checkout@v3
        with:
          repository: hexojs/hexo-starter
          ref: dcd18588de8f5c1bcc689c101e2f21726c11c4d6  # pin blog dependencies to support node.js 14
      - uses: actions/checkout@v3
        with:
          path: themes/icarus
      - uses: actions/checkout@v3
        with:
          repository: SukkaLab/hexo-many-posts
          path: source/_posts/hexo-many-posts
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      - uses: actions/cache@v3
        with:
          path: node_modules
          key: npm-cache
          restore-keys: npm-cache
      - run: npm install
      - run: >
          npm install $(node -e "const deps=require('./themes/icarus/package.json').dependencies;
          console.log(Object.keys(deps).map(key=>key+'@'+deps[key]).join(' '));")
      - run: npm install hexo-tag-embed
      - run: npx hexo config theme icarus
      - run: time NODE_ENV=production npx hexo g -b


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

_config*.yml*
yarn.lock

# Intellij Idea config file
.idea
*.ipr
*.iws
*.iml

================================================
FILE: .npmignore
================================================
.github/
.eslintignore
.eslintrc.json
.travis.yml
yarn.lock


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines

## Code styles

Please refer to the [.eslintrc.json](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.eslintrc.json).
You can also use `npm run lint` or `yarn lint` to fix code style issues.

## Project versioning

We use [SemVer](http://semver.org/) for versioning.
Any changes to the code base should not be released using an existing version.

## Commit message format

The commit message should follow the [Bluejava commit message format](https://github.com/bluejava/git-commit-guide).
The supported scopes are:

- **core** for changes related to Hexo extensions and theme-specific functions
- **comment** for comment plugin layout, schema, style, or script changes
- **share** for share plugin layout, schema, style, or script changes
- **donate** for donation plugin layout, schema, style, or script changes
- **search** for search plugin layout, schema, style, or script changes
- **widget** for widget layout, schema, style, or script changes
- **plugin** for other plugin layout, schema, style, or script changes
- **i18n** for adding or updating translations
- **test** for testing or linting-related commits
- **build** for build scripts, CI, other development or deployment related commits
- use __\*__ or leave empty to refer to commits that do not have a clear scope

## Submit changes

1. Fork this repository, make changes to it, and run it against some actual Hexo sites to see if 
anything is broken.
You should also run `npm run lint` or `yarn lint` to find and fix any code formatting issue.
2. Submit a pull request to our repository. Please make sure you followed the instructions
above.
3. We will review the pull request regularly and inform you of our questions and any changes 
that need to be made before we can merge your pull request.
4. We expect your response within two weeks, after which your pull request may be closed if
no activity is shown.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2020 PPOffice

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center" class="mb-2">
<img class="not-gallery-item" height="48" src="https://ppoffice.github.io/hexo-theme-icarus/img/logo.svg">
<br> A simple, delicate, and modern theme for the static site generator Hexo.
<br>
<a href="https://ppoffice.github.io/hexo-theme-icarus/">Preview</a> |
<a href="https://ppoffice.github.io/hexo-theme-icarus/categories/">Documentation</a> |
<a href="https://github.com/ppoffice/hexo-theme-icarus/discussions">Discuss on GitHub</a>
<br>
</p>

![](https://ppoffice.github.io/hexo-theme-icarus/gallery/preview.png?1 "Icarus Preview")

## :cd: Installation

```shell
$ npm install hexo-theme-icarus
$ hexo config theme icarus
```

Please refer to [Getting Started with Icarus](https://ppoffice.github.io/hexo-theme-icarus/uncategorized/getting-started-with-icarus/) 
for more details.

## :gift: Features

### Cyberpunk Theme Variant

Tap into the future cyber world with the newly added Cyberpunk theme variant.
Inspired by [Cyberpunk 2077](https://www.cyberpunk.net).

![Icarus Cyberpunk](https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/cyberpunk.png "Icarus Cyberpunk")

### Extensive Plugin Support

Icarus includes plentiful search, comment, sharing and other plugins out of the box that makes your
blog feature-rich and powerful.

**[Comment](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/)**

Changyan &middot; Disqus &middot; DisqusJS &middot; Facebook &middot; Gitalk &middot; Gitment &middot;
Isso &middot; LiveRe &middot; Utterance &middot; Valine

**[Donate Button](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/)**

Afdian.net &middot; Alipay &middot; Buy me a coffee &middot; Patreon &middot; Paypal &middot; Wecat

**[Search](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/)**

Algolia &middot; Baidu &middot; Google CSE &middot; Insight

**[Share](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/)**

AddThis &middot; AddToAny &middot; Baidu Share &middot; Share.js &middot; ShareThis

**[Widgets](https://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/)**

Google Adsense &middot; Archives &middot; Categories &middot; External Site Links &middot; 
Recent Posts &middot; Google Feedburner &middot; Tags &middot; Table of Contents

**[Analytics](https://ppoffice.github.io/hexo-theme-icarus/Plugins/Analytics/icarus-user-guide-web-analytics-plugins/)**

Baidu Statistics &middot; Bing Webmaster &middot; BuSuanZi Web Counter &middot; CNZZ Statistics &middot;
Google Analytics &middot; Hotjar &middot; StatCounter &middot; Twitter Conversion Tracking

**[Other Plugins](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/)**

Cookie Consent &middot; LightGallery &middot; Justified Gallery &middot; KaTeX &middot; MathJax &middot;
Oudated Browser &middot; Page Loading Animations

### Colorful Code Highlight

Icarus directly import stylesheets from the [highlight.js](https://highlightjs.org/) package and makes more than
90 code highlight themes available to you.

<table>
    <tr>
        <th>Atom One Light</th>
        <th>Monokai</th>
        <th>Kimbie Dark</th>
    </tr>
    <tr>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/atom-one-light.png?2"></td>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/monokai.png?2"></td>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/kimbie-dark.png?2"></td>
    </tr>
</table>

### Flexible Theme Configuration

Icarus allows you to configure your site on a per-page or per-layout basis.

<div>
<table>
    <tr>
        <th>_config.yml</th>
        <th>post.md</th>
        <th>_config.page.yml</th>
    </tr>
    <tr>
        <td>
<pre>widgets:
  - type: profile
    position: left
  - type: recent_posts
    position: right</pre>
        </td>
        <td>
<pre>widgets:
  - type: profile
    position: left
  - type: recent_posts
    position: left</pre>
        </td>
        <td>
<pre>widgets: null
 
 
 
</pre>
        </td>
    </tr>
    <tr>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/default-config.png"></td>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/post-config.png"></td>
        <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/layout-config.png"></td>
    </tr>
</table>
</div>

### Responsive Layout

Give your audiences best viewing experience with Icarus's mobile-friendly responsive layout.

![Responsive Layout](https://ppoffice.github.io/hexo-theme-icarus/gallery/responsive.png)

## :hammer: Development

This project is built with

- [Hexo](https://hexo.io/)
- [Inferno.js](https://infernojs.org/)
- [Stylus](https://stylus-lang.com/)
- [Bulma](https://bulma.io/)

Please refer to the [documentation](https://ppoffice.github.io/hexo-theme-icarus/categories/) and 
[contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) for implementation details.

## :tada: Contribute

If you feel like to help us build a better Icarus, you can

:black_nib: [Submit a tutorial](https://github.com/ppoffice/hexo-theme-icarus/new/site/source/_posts) |
:earth_asia: [Add a translation](https://github.com/ppoffice/hexo-theme-icarus/tree/master/languages) |
:triangular_flag_on_post: [Report a bug](https://github.com/ppoffice/hexo-theme-icarus/issues) |
:electric_plug: [Suggest a new feature](https://github.com/ppoffice/hexo-theme-icarus/pulls)

## :memo: License

This project is licensed under the MIT License - see the [LICENSE](https://github.com/ppoffice/hexo-theme-icarus/blob/master/LICENSE) file for details.


================================================
FILE: include/config.js
================================================
/* eslint no-process-exit: "off" */
const fs = require('fs');
const path = require('path');
const util = require('util');
const crypto = require('crypto');
const createLogger = require('hexo-log');
const yaml = require('hexo-component-inferno/lib/util/yaml');
const { Migrator } = require('hexo-component-inferno/lib/core/migrate');
const { SchemaLoader } = require('hexo-component-inferno/lib/core/schema');
const { yellow } = require('./util/console');

const logger = createLogger.default();

function loadThemeConfig(hexo, cfgPaths) {
    const configs = cfgPaths.map(cfgPath => fs.readFileSync(cfgPath))
        .map(cfgPath => yaml.parse(cfgPath));
    return Object.assign({}, ...configs, hexo.config.theme_config);
}

function generateThemeConfigFile(schema, cfgPath) {
    const defaultValue = schema.getDefaultValue();
    fs.writeFileSync(cfgPath, defaultValue.toYaml());
}

function hashConfigFile(cfgPath) {
    const content = fs.readFileSync(cfgPath);
    return crypto.createHash('md5').update(content).digest('hex');
}

function checkConfig(hexo) {
    if (!process.argv.includes('--icarus-dont-check-config')) {
        logger.info('=== Checking theme configurations ===');

        const siteCfgFile = path.join(hexo.base_dir, '_config.yml');
        const themeSiteCfg = path.join(hexo.base_dir, '_config.icarus.yml');
        const themeDirCfg = path.join(hexo.theme_dir, '_config.yml');
        const themeCfgPaths = [themeDirCfg, themeSiteCfg].filter(cfgPath => fs.existsSync(cfgPath));
        const themeSiteCfgExample = themeSiteCfg + '.example';

        const schemaDir = path.join(hexo.theme_dir, 'include/schema/');
        const loader = SchemaLoader.load(require(path.join(schemaDir, 'config.json')), schemaDir);
        const schema = loader.getSchema('/config.json');

        if (!process.argv.includes('--icarus-dont-generate-config')) {
            if (!themeCfgPaths.length) {
                logger.warn('None of the following configuration files is found:');
                logger.warn(`- ${yellow(themeSiteCfg)}`);
                logger.warn(`- ${yellow(themeDirCfg)}`);
                logger.info('Generating theme configuration file...');
                generateThemeConfigFile(schema, themeSiteCfg);
                themeCfgPaths.push(themeSiteCfg);
                logger.info(`${yellow(themeSiteCfg)} created successfully.`);
                logger.info('To skip configuration generation, use "--icarus-dont-generate-config".');
            }
        }

        let cfg = loadThemeConfig(hexo, themeCfgPaths);

        if (!process.argv.includes('--icarus-dont-upgrade-config')) {
            const migrator = new Migrator(require(path.join(hexo.theme_dir, 'include/migration/head')));
            if (cfg.version && migrator.isOudated(cfg.version)) {
                logger.warn(`Your theme configuration is outdated (${cfg.version} < ${migrator.getLatestVersion()}).`);
                logger.info('To skip the configuration upgrade, use "--icarus-dont-upgrade-config".');

                logger.info('Backing up theme configuration files...');
                for (const cfgPath of themeCfgPaths) {
                    const backupPath = cfgPath + '.' + hashConfigFile(cfgPath);
                    const relCfgPath = path.relative(hexo.base_dir, cfgPath);
                    const relBackupPath = path.relative(hexo.base_dir, backupPath);
                    fs.renameSync(cfgPath, backupPath);
                    logger.info(`${yellow(relCfgPath)} => ${yellow(relBackupPath)}`);
                }

                logger.info('Upgrading theme configurations...');
                cfg = migrator.migrate(cfg);
                fs.writeFileSync(themeSiteCfg, yaml.stringify(cfg));
                logger.info(`Theme configurations are written to ${yellow(themeSiteCfg)}.`);

                generateThemeConfigFile(schema, themeSiteCfgExample);
                logger.info(`Example configurations is at ${yellow(themeSiteCfgExample)}.`);
            }
        }

        const validation = schema.validate(cfg);
        if (validation !== true) {
            logger.warn('Theme configurations failed one or more checks.');
            logger.warn('Icarus may still run, but you will encounter unexcepted results.');
            logger.warn('Here is some information for you to correct the configuration file.');
            logger.warn(util.inspect(validation));
        }

        const rootCfg = yaml.parse(fs.readFileSync(siteCfgFile));
        if (rootCfg.theme_config) {
            logger.warn(`"theme_config" found in ${yellow(siteCfgFile)}.`);
            logger.warn(`Please remove theme configurations from ${yellow(siteCfgFile)}.`);
        }
    }
}

module.exports = hexo => {
    try {
        checkConfig(hexo);
    } catch (e) {
        logger.error(e);
        logger.error('Theme configuration checking failed.');
        logger.info('You may use \'--icarus-dont-check-config\' to skip configuration checking.');
        process.exit(-1);
    }
};


================================================
FILE: include/dependency.js
================================================
/* eslint no-process-exit: "off" */
const semver = require('semver');
const createLogger = require('hexo-log');
const packageInfo = require('../package.json');
const { yellow, red, green } = require('./util/console');

const logger = createLogger.default();

module.exports = hexo => {
    function checkDependency(name, reqVer) {
        try {
            require.resolve(name);
            const version = require(name + '/package.json').version;
            if (!semver.satisfies(version, reqVer)) {
                logger.error(`Package ${yellow(name)}'s version (${yellow(version)}) does not satisfy the required version (${red(reqVer)}).`);
                return false;
            }
            return true;
        } catch (e) {
            logger.error(`Package ${yellow(name)} is not installed.`);
        }
        return false;
    }

    logger.info('=== Checking package dependencies ===');
    const dependencies = Object.assign({}, packageInfo.dependencies);
    const missingDeps = Object.keys(dependencies)
        .filter(name => !checkDependency(name, dependencies[name]));
    if (missingDeps && missingDeps.length) {
        logger.error('Please install the missing dependencies your Hexo site root directory:');
        logger.error(green('npm install --save ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
        logger.error('or:');
        logger.error(green('yarn add ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
        process.exit(-1);
    }
};


================================================
FILE: include/migration/head.js
================================================
module.exports = require('./v5_v5.1');


================================================
FILE: include/migration/v2_v3.js
================================================
const createLogger = require('hexo-log');
const deepmerge = require('deepmerge');
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;

const logger = createLogger.default();

module.exports = class extends Migration {
    constructor() {
        super('3.0.0', null);
    }

    upgrade(config) {
        const result = deepmerge({}, config);
        result.head = {
            favicon: config.favicon || null,
            canonical_url: config.canonical_url || null,
            open_graph: config.open_graph || null,
            meta: config.meta || null,
            rss: config.rss || null
        };
        delete result.favicon;
        delete result.canonical_url;
        delete result.open_graph;
        delete result.meta;
        delete result.rss;

        if (result.logo === '/images/logo.svg') {
            result.logo = result.logo.replace(/^\/images/, '/img');
        }

        if (result.head.favicon === '/img/favicon.svg') {
            result.head.favicon = result.head.favicon.replace(/^\/images/, '/img');
        }

        if (result.search && Object.prototype.hasOwnProperty.call(result.search, 'type')) {
            switch (result.search.type) {
                case 'google-cse':
                    result.search.type = 'google_cse';
                    break;
            }
        }

        if (result.comment && Object.prototype.hasOwnProperty.call(result.comment, 'type')) {
            switch (result.comment.type) {
                case 'changyan':
                    result.comment.app_id = config.comment.appid;
                    delete result.comment.appid;
                    break;
            }
        }

        if (Array.isArray(result.donate) && result.donate.length) {
            result.donates = result.donate;
            delete result.donate;
        }

        if (Array.isArray(result.widgets) && result.widgets.length) {
            for (const widget of result.widgets) {
                if (Object.prototype.hasOwnProperty.call(widget, 'type')) {
                    switch (widget.type) {
                        case 'archive':
                            widget.type = 'archives';
                            break;
                        case 'category':
                            widget.type = 'categories';
                            break;
                        case 'tag':
                            widget.type = 'tags';
                            break;
                        case 'tagcloud':
                            logger.warn('The tagcloud widget has been removed from Icarus in version 3.0.0.');
                            logger.warn('Please remove it from your configuration file.');
                            break;
                    }
                }
            }
        }

        if (result.plugins && typeof result.plugins === 'object') {
            for (const name in result.plugins) {
                switch (name) {
                    case 'outdated-browser':
                        result.plugins.outdated_browser = result.plugins[name];
                        delete result.plugins[name];
                        break;
                    case 'back-to-top':
                        result.plugins.back_to_top = result.plugins[name];
                        delete result.plugins[name];
                        break;
                    case 'baidu-analytics':
                        result.plugins.baidu_analytics = result.plugins[name];
                        delete result.plugins[name];
                        break;
                    case 'google-analytics':
                        result.plugins.google_analytics = result.plugins[name];
                        delete result.plugins[name];
                        break;
                }
            }
        }

        return result;
    }
};


================================================
FILE: include/migration/v3_v4.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;

module.exports = class extends Migration {
    constructor() {
        super('4.0.0', null);
    }

    upgrade(config) {
        if (typeof config.article === 'object') {
            delete config.article.thumbnail;
        }
        return config;
    }
};


================================================
FILE: include/migration/v4_v5.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;

module.exports = class extends Migration {
    constructor() {
        super('5.0.0', null);
    }

    upgrade(config) {
        return config;
    }
};


================================================
FILE: include/migration/v5_v5.1.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;

module.exports = class extends Migration {
    constructor() {
        super('5.1.0', null);
    }

    upgrade(config) {
        // Upgrade Waline configurations from v1 to v2.
        const comment = config.comment || {};
        const renamedOptions = {
            'visitor': 'pageview',
            'uploadImage': 'image_uploader',
            'highlight': 'highlighter',
            'math': 'tex_renderer'
        };
        if (comment.type === 'waline') {
            for (const option in renamedOptions) {
                if (typeof comment[option] !== 'undefined') {
                    if (typeof comment[renamedOptions[option]] === 'undefined') {
                        comment[renamedOptions[option]] = comment[option];
                    }
                    delete comment[option];
                }
            }
        }
        return config;
    }
};


================================================
FILE: include/register.js
================================================
const createLogger = require('hexo-log');

const logger = createLogger.default();

module.exports = hexo => {
    logger.info('=== Registering Hexo extensions ===');
    require('hexo-component-inferno/lib/hexo/filter/locals')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/assets')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/insight')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/categories')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/category')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/manifest')(hexo);
    require('hexo-component-inferno/lib/hexo/generator/tags')(hexo);
    require('hexo-component-inferno/lib/hexo/helper/cdn')(hexo);
    require('hexo-component-inferno/lib/hexo/helper/page')(hexo);
    require('hexo-component-inferno/lib/hexo/tag/message')(hexo);
    require('hexo-component-inferno/lib/hexo/tag/tabs')(hexo);
    require('hexo-component-inferno/lib/core/view').init(hexo);
};


================================================
FILE: include/schema/comment/.gitkeep
================================================


================================================
FILE: include/schema/common/article.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/article.json",
    "description": "Article related configurations",
    "type": "object",
    "properties": {
        "highlight": {
            "type": "object",
            "description": "Code highlight settings",
            "properties": {
                "theme": {
                    "type": "string",
                    "description": "Code highlight themes\nhttps://github.com/highlightjs/highlight.js/tree/master/src/styles",
                    "default": "atom-one-light",
                    "nullable": true
                },
                "clipboard": {
                    "type": "boolean",
                    "description": "Show copy code button",
                    "default": true,
                    "nullable": true
                },
                "fold": {
                    "type": "string",
                    "description": "Default folding status of the code blocks. Can be \"\", \"folded\", \"unfolded\"",
                    "enum": [
                        "",
                        "folded",
                        "unfolded"
                    ],
                    "default": "unfolded",
                    "nullable": true
                }
            },
            "nullable": true
        },
        "readtime": {
            "type": "boolean",
            "description": "Whether to show estimated article reading time",
            "default": true,
            "nullable": true
        },
        "update_time": {
            "type": ["boolean", "string"],
            "description": "Whether to show updated time. For \"auto\", shows article update time only when page.updated is set and it is different from page.date",
            "default": true,
            "enum": [true, false, "auto"],
            "nullable": true
        },
        "licenses": {
            "$ref": "/misc/poly_links.json",
            "description": "Article licensing block",
            "examples": [
                {
                    "Creative Commons": {
                      "icon": "fab fa-creative-commons",
                      "url": "https://creativecommons.org/"
                    },
                    "Attribution": {
                      "icon": "fab fa-creative-commons-by",
                      "url": "https://creativecommons.org/licenses/by/4.0/"
                    },
                    "Noncommercial": {
                      "icon": "fab fa-creative-commons-nc",
                      "url": "https://creativecommons.org/licenses/by-nc/4.0/"
                    }
                }
            ]
        }
    }
}

================================================
FILE: include/schema/common/comment.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/comment.json",
    "description": "Comment plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/",
    "type": "object",
    "oneOf": [
        {
            "$ref": "/comment/disqus.json"
        },
        {
            "$ref": "/comment/changyan.json"
        },
        {
            "$ref": "/comment/disqusjs.json"
        },
        {
            "$ref": "/comment/facebook.json"
        },
        {
            "$ref": "/comment/giscus.json"
        },
        {
            "$ref": "/comment/gitalk.json"
        },
        {
            "$ref": "/comment/gitment.json"
        },
        {
            "$ref": "/comment/isso.json"
        },
        {
            "$ref": "/comment/livere.json"
        },
        {
            "$ref": "/comment/utterances.json"
        },
        {
            "$ref": "/comment/valine.json"
        },
        {
            "$ref": "/comment/waline.json"
        },
        {
            "$ref": "/comment/twikoo.json"
        }
    ]
}


================================================
FILE: include/schema/common/donates.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/donates.json",
    "description": "Donate plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/",
    "type": "array",
    "items": {
        "type": "object",
        "oneOf": [
            {
                "$ref": "/donate/afdian.json"
            },
            {
                "$ref": "/donate/alipay.json"
            },
            {
                "$ref": "/donate/buymeacoffee.json"
            },
            {
                "$ref": "/donate/patreon.json"
            },
            {
                "$ref": "/donate/paypal.json"
            },
            {
                "$ref": "/donate/wechat.json"
            }
        ]
    }
}

================================================
FILE: include/schema/common/footer.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/footer.json",
    "description": "Page footer configurations",
    "type": "object",
    "properties": {
        "copyright": {
            "description": "Copyright text",
            "type": "string",
            "examples": [
                "© 2019",
                "© 2019 - 2020",
                "© 2019 - 2020, Company Name",
                "© 2019 - 2020, Company Name. All rights reserved.",
                "粤ICP备12345678号"
            ]
        },
        "links": {
            "$ref": "/misc/poly_links.json",
            "description": "Links to be shown on the right of the footer section",
            "examples": [
                {
                    "Creative Commons": {
                        "icon": "fab fa-creative-commons",
                        "url": "https://creativecommons.org/"
                    },
                    "Attribution 4.0 International": {
                        "icon": "fab fa-creative-commons-by",
                        "url": "https://creativecommons.org/licenses/by/4.0/"
                    },
                    "Download on GitHub": {
                        "icon": "fab fa-github",
                        "url": "https://github.com/ppoffice/hexo-theme-icarus"
                    }
                }
            ]
        }
    }
}

================================================
FILE: include/schema/common/head.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/head.json",
    "description": "Page metadata configurations",
    "type": "object",
    "properties": {
        "favicon": {
            "type": "string",
            "description": "URL or path to the website's icon",
            "default": "/img/favicon.svg",
            "nullable": true
        },
        "manifest": {
            "$ref": "/misc/manifest.json"
        },
        "open_graph": {
            "$ref": "/misc/open_graph.json"
        },
        "structured_data": {
            "$ref": "/misc/structured_data.json"
        },
        "meta": {
            "$ref": "/misc/meta.json"
        },
        "rss": {
            "type": "string",
            "description": "URL or path to the website's RSS atom.xml",
            "nullable": true
        }
    }
}

================================================
FILE: include/schema/common/navbar.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/navbar.json",
    "description": "Page top navigation bar configurations",
    "type": "object",
    "properties": {
        "menu": {
            "type": "object",
            "description": "Navigation menu items",
            "patternProperties": {
                ".+": {
                    "type": "string",
                    "description": "URL or path of the menu link"
                }
            },
            "examples": [
                {
                    "Home": "/",
                    "Archives": "/archives",
                    "Categories": "/categories",
                    "Tags": "/tags",
                    "About": "/about"
                }
            ],
            "nullable": true
        },
        "links": {
            "$ref": "/misc/poly_links.json",
            "description": "Links to be shown on the right of the navigation bar",
            "examples": [
                {
                    "Download on GitHub": {
                        "icon": "fab fa-github",
                        "url": "https://github.com/ppoffice/hexo-theme-icarus"
                    }
                }
            ]
        }
    }
}

================================================
FILE: include/schema/common/plugins.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/plugins.json",
    "description": "Plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/",
    "type": "object",
    "properties": {
        "animejs": {
            "$ref": "/plugin/animejs.json"
        },
        "back_to_top": {
            "$ref": "/plugin/back_to_top.json"
        },
        "baidu_analytics": {
            "$ref": "/plugin/baidu_analytics.json"
        },
        "bing_webmaster": {
            "$ref": "/plugin/bing_webmaster.json"
        },
        "busuanzi": {
            "$ref": "/plugin/busuanzi.json"
        },
        "cnzz": {
            "$ref": "/plugin/cnzz.json"
        },
        "cookie_consent": {
            "$ref": "/plugin/cookie_consent.json"
        },
        "gallery": {
            "$ref": "/plugin/gallery.json"
        },
        "google_analytics": {
            "$ref": "/plugin/google_analytics.json"
        },
        "hotjar": {
            "$ref": "/plugin/hotjar.json"
        },
        "katex": {
            "$ref": "/plugin/katex.json"
        },
        "mathjax": {
            "$ref": "/plugin/mathjax.json"
        },
        "outdated_browser": {
            "$ref": "/plugin/outdated_browser.json"
        },
        "pjax": {
            "$ref": "/plugin/pjax.json"
        },
        "progressbar": {
            "$ref": "/plugin/progressbar.json"
        },
        "statcounter": {
            "$ref": "/plugin/statcounter.json"
        },
        "twitter_conversion_tracking": {
            "$ref": "/plugin/twitter_conversion_tracking.json"
        }
    }
}

================================================
FILE: include/schema/common/providers.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/providers.json",
    "description": "CDN provider settings\nhttps://ppoffice.github.io/hexo-theme-icarus/Configuration/Theme/speed-up-your-site-with-custom-cdn/",
    "type": "object",
    "properties": {
        "cdn": {
            "type": "string",
            "description": "Name or URL template of the JavaScript and/or stylesheet CDN provider",
            "default": "jsdelivr",
            "nullable": true
        },
        "fontcdn": {
            "type": "string",
            "description": "Name or URL template of the webfont CDN provider",
            "default": "google",
            "nullable": true
        },
        "iconcdn": {
            "type": "string",
            "description": "Name or URL of the fontawesome icon font CDN provider",
            "default": "fontawesome",
            "nullable": true
        }
    }
}

================================================
FILE: include/schema/common/search.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/search.json",
    "description": "Search plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/",
    "type": "object",
    "oneOf": [
        {
            "$ref": "/search/insight.json"
        },
        {
            "$ref": "/search/baidu.json"
        },
        {
            "$ref": "/search/google_cse.json"
        },
        {
            "$ref": "/search/algolia.json"
        }
    ]
}

================================================
FILE: include/schema/common/share.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/share.json",
    "description": "Share plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/",
    "type": "object",
    "oneOf": [
        {
            "$ref": "/share/sharethis.json"
        },
        {
            "$ref": "/share/addthis.json"
        },
        {
            "$ref": "/share/addtoany.json"
        },
        {
            "$ref": "/share/bdshare.json"
        },
        {
            "$ref": "/share/sharejs.json"
        }
    ]
}

================================================
FILE: include/schema/common/sidebar.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/sidebar.json",
    "description": "Sidebar configurations.\nPlease be noted that a sidebar is only visible when it has at least one widget",
    "type": "object",
    "properties": {
        "left": {
            "type": "object",
            "description": "Left sidebar configurations",
            "properties": {
                "sticky": {
                    "type": "boolean",
                    "description": "Whether the sidebar sticks to the top when page scrolls",
                    "default": false
                }
            }
        },
        "right": {
            "type": "object",
            "description": "Right sidebar configurations",
            "properties": {
                "sticky": {
                    "type": "boolean",
                    "description": "Whether the sidebar sticks to the top when page scrolls",
                    "default": false
                }
            }
        }
    }
}

================================================
FILE: include/schema/common/widgets.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/common/widgets.json",
    "description": "Sidebar widget configurations\nhttp://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/",
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "position": {
                "type": "string",
                "description": "Where should the widget be placed, left sidebar or right sidebar",
                "default": "left"
            }
        },
        "oneOf": [
            {
                "$ref": "/widget/profile.json"
            },
            {
                "$ref": "/widget/toc.json"
            },
            {
                "$ref": "/widget/links.json"
            },
            {
                "$ref": "/widget/categories.json"
            },
            {
                "$ref": "/widget/recent_posts.json"
            },
            {
                "$ref": "/widget/archives.json"
            },
            {
                "$ref": "/widget/tags.json"
            },
            {
                "$ref": "/widget/subscribe_email.json"
            },
            {
                "$ref": "/widget/adsense.json"
            },
            {
                "$ref": "/widget/followit.json"
            }
        ],
        "required": [
            "position"
        ]
    }
}

================================================
FILE: include/schema/config.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/config.json",
    "description": "The configuration file definition",
    "type": "object",
    "properties": {
        "version": {
            "type": "string",
            "description": "Version of the configuration file",
            "default": "5.1.0"
        },
        "variant": {
            "type": "string",
            "description": "Icarus theme variant, can be \"default\" or \"cyberpunk\"",
            "enum": [
                "default",
                "cyberpunk"
            ],
            "default": "default"
        },
        "logo": {
            "type": [
                "string",
                "object"
            ],
            "description": "Path or URL to the website's logo",
            "default": "/img/logo.svg",
            "properties": {
                "text": {
                    "type": "string",
                    "description": "Text to be shown in place of the logo image"
                }
            },
            "required": [
                "text"
            ]
        },
        "head": {
            "$ref": "/common/head.json"
        },
        "navbar": {
            "$ref": "/common/navbar.json"
        },
        "footer": {
            "$ref": "/common/footer.json"
        },
        "article": {
            "$ref": "/common/article.json"
        },
        "search": {
            "$ref": "/common/search.json"
        },
        "comment": {
            "$ref": "/common/comment.json"
        },
        "donates": {
            "$ref": "/common/donates.json"
        },
        "share": {
            "$ref": "/common/share.json"
        },
        "sidebar": {
            "$ref": "/common/sidebar.json"
        },
        "widgets": {
            "$ref": "/common/widgets.json"
        },
        "plugins": {
            "$ref": "/common/plugins.json"
        },
        "providers": {
            "$ref": "/common/providers.json"
        }
    },
    "required": [
        "version"
    ]
}

================================================
FILE: include/schema/donate/.gitkeep
================================================


================================================
FILE: include/schema/misc/.gitkeep
================================================


================================================
FILE: include/schema/plugin/animejs.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/plugin/animejs.json",
    "description": "Enable page startup animations",
    "type": "boolean",
    "default": true
}

================================================
FILE: include/schema/plugin/back_to_top.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/plugin/back_to_top.json",
    "description": "Show the \"back to top\" button",
    "type": "boolean",
    "default": true
}

================================================
FILE: include/schema/plugin/pjax.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/plugin/pjax.json",
    "description": "Enable PJAX",
    "type": "boolean",
    "default": true
}

================================================
FILE: include/schema/search/.gitkeep
================================================


================================================
FILE: include/schema/share/.gitkeep
================================================


================================================
FILE: include/schema/widget/profile.json
================================================
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "/widget/profile.json",
    "description": "Profile widget configurations",
    "type": "object",
    "properties": {
        "type": {
            "type": "string",
            "const": "profile",
            "nullable": true
        },
        "author": {
            "type": "string",
            "description": "Author name",
            "examples": [
                "Your name"
            ],
            "nullable": true
        },
        "author_title": {
            "type": "string",
            "description": "Author title",
            "examples": [
                "Your title"
            ],
            "nullable": true
        },
        "location": {
            "type": "string",
            "description": "Author's current location",
            "examples": [
                "Your location"
            ],
            "nullable": true
        },
        "avatar": {
            "type": "string",
            "description": "URL or path to the avatar image",
            "nullable": true
        },
        "avatar_rounded": {
            "type": "boolean",
            "description": "Whether show the rounded avatar image",
            "default": false,
            "nullable": true
        },
        "gravatar": {
            "type": "string",
            "description": "Email address for the Gravatar",
            "nullable": true
        },
        "follow_link": {
            "type": "string",
            "description": "URL or path for the follow button",
            "examples": [
                "https://github.com/ppoffice"
            ],
            "nullable": true
        },
        "social_links": {
            "$ref": "/misc/poly_links.json",
            "description": "Links to be shown on the bottom of the profile widget",
            "examples": [
                {
                    "Github": {
                        "icon": "fab fa-github",
                        "url": "https://github.com/ppoffice"
                    },
                    "Facebook": {
                        "icon": "fab fa-facebook",
                        "url": "https://facebook.com"
                    },
                    "Twitter": {
                        "icon": "fab fa-twitter",
                        "url": "https://twitter.com"
                    },
                    "Dribbble": {
                        "icon": "fab fa-dribbble",
                        "url": "https://dribbble.com"
                    },
                    "RSS": {
                        "icon": "fas fa-rss",
                        "url": "/"
                    }
                }
            ]
        }
    },
    "required": [
        "type"
    ]
}

================================================
FILE: include/style/article.styl
================================================
/* ---------------------------------
 *    Article Summary and Content
 * --------------------------------- */
$article-font-size ?= 1.1rem

article
    &.media
        color: $text-light

        a
            color: inherit

            &:hover
                color: $primary

        .image
            width: 64px
            height: 64px

            img
                object-fit: cover
                width: 100%
                height: 100%

        .title
            @extend .is-size-6
            margin-bottom: .25em

        .date, .categories
            @extend .is-size-7

        .categories
            @extend .is-uppercase

        .media-content
            color: $text-light

            .title
                margin: 0
                line-height: inherit

    &.article
        .article-meta, .article-tags
            color: $text-light

        .article-meta
            overflow-x: auto
            margin-bottom: .5rem

        .article-more
            @extend .button.is-light

        .content
            word-wrap: break-word
            font-size: $article-font-size

            h1
                font-size: 1.75em

            h2
                font-size: 1.5em

            h3
                font-size: 1.25em

            h4
                font-size: 1.125em

            h5
                font-size: 1em

            pre
                font-size: .85em

            code
                padding: 0
                background: transparent
                overflow-wrap: break-word

            blockquote
                &.pullquote
                    float: right
                    max-width: 50%
                    font-size: 1.15rem
                    position: relative

                footer
                    strong + cite
                        margin-left: .5em

            .message.message-immersive
                border-radius: 0
                margin: 0 0 - $card-content-padding $card-content-padding 0 - $card-content-padding

                .message-body
                    border: none
        
        .article-tags
            display: flex
            flex-wrap: wrap

.rtl
    direction: rtl

    .level
        &, &.is-mobile
            .level-item:not(:last-child)
                margin-left: .75rem
                margin-right: 0

// Overflow table
.table-overflow
    overflow-x: auto

    table
        width: auto !important

        th
            word-break: keep-all

// Video container
.video-container
    position: relative
    padding-bottom: 56.25%
    padding-top: 25px
    height: 0

    iframe
        position: absolute
        top: 0
        left: 0
        width: 100%
        height: 100%

.article-licensing
    position: relative
    z-index: 1
    box-shadow: none
    background: $white-ter
    border-radius: $radius
    overflow: hidden

    &:after
        position: absolute
        z-index: -1
        right: -50px
        top: -87.87px
        content: '\f25e'
        font-size: 200px
        font-family: 'Font Awesome 5 Brands'
        opacity: .1

    .level-left
        flex-wrap: wrap
        max-width: 100%

    .licensing-title
        @extend .mb-3
        line-height: 1.2

        p:not(:last-child)
            @extend .mb-1

        a
            @extend .is-size-7, .has-text-grey

    .licensing-meta
        .level-item
            @extend .mr-4

        .icons
            .icon
                @extend .ml-1
                width: 1.2em
                height: 1.2em
                font-size: 1.2em
                vertical-align: bottom

        h6
            @extend .is-size-7

        a
            color: inherit

a
    &.article-nav-prev
        span
            text-align: left
            flex-shrink: 1
            word-wrap: break-word
            white-space: normal

    &.article-nav-next
        span
            text-align: right
            flex-shrink: 1
            word-wrap: break-word
            white-space: normal

================================================
FILE: include/style/base.styl
================================================
bulma-stylus-root = '../../../../node_modules/bulma-stylus/stylus'

/* ---------------------------------
 *   Override Bulma CSS Framework
 * --------------------------------- */
$body-size ?= 14px
$body-background-color ?= #f7f7f7

$family-sans-serif ?= Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif
$family-code ?= 'Source Code Pro', monospace, 'Microsoft YaHei'

$size-7 ?= .85rem
$size-small ?= .75rem

$primary ?= $blue
$custom-colors ?= {
    grey-lightest: {
        '1': $grey-lightest
        '2': $grey-darker
    }
}

$navbar-item-active-color ?= $primary
$footer-background-color ?= $scheme-main

$gap ?= 64px
$tablet ?= 769px
$desktop ?= 1088px
$widescreen ?= 1280px
$fullhd ?= 1472px

$shadow ?= 0 4px 10px rgba(0, 0, 0, 0.05)

$title-weight ?= $weight-normal

$control-height ?= 2.25em
$button-padding-vertical ?= calc(0.375em - 1px)

$card-radius ?= $radius
$card-media-margin ?= 0.75rem
$card-shadow ?= $shadow, 0 0 1px rgba(0, 0, 0, 0.1)

$menu-item-active-color ?= $link
$menu-item-active-background-color ?= hsl(219, 70%, 96%)

$content-heading-weight ?= $weight-normal


$logo-height ?= 1.75rem

// FIXME: https://github.com/groenroos/bulma-stylus/issues/11
@import bulma-stylus-root + '/utilities/initial-variables'
@import bulma-stylus-root + '/utilities/functions'
@import bulma-stylus-root + '/utilities/derived-variables'

$colors = merge($colors, $custom-colors)

@import bulma-stylus-root + '/utilities/animations'
@import bulma-stylus-root + '/utilities/mixins'
@import bulma-stylus-root + '/utilities/controls'
@import bulma-stylus-root + '/base/_all'
@import bulma-stylus-root + '/components/_all'
@import bulma-stylus-root + '/elements/_all'
@import bulma-stylus-root + '/form/_all'
@import bulma-stylus-root + '/grid/_all'
@import bulma-stylus-root + '/layout/_all'

html
    height: 100%
    -webkit-text-size-adjust: 100%
    -moz-text-size-adjust: 100%
    -ms-text-size-adjust: 100%
    text-size-adjust: 100%

body
    min-height: 100%
    display: flex
    flex-direction: column

body > .section
    flex-grow: 1

+desktop()
    ::-webkit-scrollbar
        width: 8px
        height: 8px

    ::-webkit-scrollbar-track
        border-radius: 3px
        background: rgba(0,0,0,0.06)
        box-shadow: inset 0 0 5px rgba(0,0,0,0.1)

    ::-webkit-scrollbar-thumb
        border-radius: 3px
        background: rgba(0,0,0,0.12)
        box-shadow: inset 0 0 10px rgba(0,0,0,0.2)

    ::-webkit-scrollbar-thumb:hover
        background: rgba(0,0,0,0.24)


================================================
FILE: include/style/button.styl
================================================
/* ---------------------------------
 *            Buttons
 * --------------------------------- */
.button
    &.is-transparent
        color: inherit
        background: transparent
        border-color: transparent


================================================
FILE: include/style/card.styl
================================================
/* ---------------------------------
 *              Card
 * --------------------------------- */
.card
    overflow: visible
    border-radius: $card-radius

    & + .card, & + .column-right-shadow
        margin-top: 1.5rem

    .card-image
        overflow: hidden
        border-top-left-radius: $card-radius
        border-top-right-radius: $card-radius

    .media + .media
        border: none
        margin-top: 0


================================================
FILE: include/style/codeblock.styl
================================================
/* ---------------------------------
 *          Code Highlight
 * --------------------------------- */
$codeblock-caption-bg ?= rgba(200, 200, 200, .15)

figure.highlight
    padding: 0
    width: 100%
    position: relative
    margin: 1em 0 1em !important
    border-radius: $radius

    &.folded
        .highlight-body
            height: 0

    .copy
        opacity: .7

    pre, table tr:hover
        color: inherit
        background: transparent

    table
        width: auto

        tr td
            border: none

        tr:not(:first-child) td
            padding-top: 0

        tr:not(:last-child) td
            padding-bottom: 0

    pre
        padding: 0
        overflow: visible

        .line, code .hljs
            line-height: 1.5rem

    figcaption, .gutter
        background: $codeblock-caption-bg

    figcaption
        margin: 0 !important
        padding: .3em 0em .3em .75em
        font-style: normal
        font-size: .8em

        *
            color: inherit

        span
            font-weight: 500
            font-family: $family-code

        .level-left *:not(:last-child)
            margin-right: .5em

        .level-right *:not(:first-child)
            margin-left: .5em

        .fold
            cursor: pointer

        &.level
            overflow: auto

            .level-right
                a
                    padding: 0em .75em

    .highlight-body
        overflow: auto

    .gutter
        text-align: right

    .tag, .title, .number, .section
        display: inherit
        font: inherit
        margin: inherit
        padding: inherit
        background: inherit
        height: inherit
        text-align: inherit
        vertical-align: inherit
        min-width: inherit
        border-radius: inherit

figure.highlight.foldable
  div.level-left
    cursor: pointer  // clicking the codeblock filename can toggle folding 

/* ---------------------------------
 *        Fix Gist Snippet
 * --------------------------------- */
.gist
    table
        tr:hover
            background: transparent

        td
            border: none

    .file
        all: initial


================================================
FILE: include/style/donate.styl
================================================
/* ---------------------------------
 *          Donate Buttons
 * --------------------------------- */
$donate-qrcode-max-width ?= 280px
$donate-qrcode-shadow ?= $card-shadow
$donate-qrcode-box-radius ?= $card-radius

$donate-button-colors ?= {
    'afdian': rgb(136, 95, 217),
    'alipay': rgb(0, 160, 232),
    'buymeacoffee': rgb(255, 221, 0),
    'paypal': rgb(254, 183, 0),
    'patreon': rgb(255, 66, 77),
    'wechat': rgb(26, 173, 25),
}

.donate
    position: relative

    .qrcode
        display: none
        position: absolute
        z-index: 99
        bottom: 2.5em
        line-height: 0
        overflow: hidden
        box-shadow: $donate-qrcode-shadow
        border-radius: $donate-qrcode-box-radius

        img
            max-width: $donate-qrcode-max-width

    &:hover
        .qrcode
            display: block

    &:first-child:not(:last-child)
        .qrcode
            left: -.75rem

    &:last-child:not(:first-child)
        .qrcode
            right: -.75rem

    for $name, $color in $donate-button-colors
        &[data-type={'"' + $name + '"'}]
            color: findColorInvert($color)
            background-color: $color
            border-color: transparent

            &:active
                background-color: darken($color, 5%)

            &:hover
                background-color: darken($color, 2.5%)

            &:focus:not(:active)
                box-shadow: 0 0 0 .125em rgba($color, .25)


================================================
FILE: include/style/footer.styl
================================================
/* ---------------------------------
 *            Page Footer
 * --------------------------------- */
footer.footer
    .level-start
        +mobile()
            text-align: center

    .level-end
        .field
            flex-wrap: wrap
            align-items: center

            +mobile()
                justify-content: center
                margin-top: 1rem

.footer-logo
    img
        max-height: $logo-height


================================================
FILE: include/style/helper.styl
================================================
/* ---------------------------------
 *          Spacing helpers
 * --------------------------------- */
$spacer ?= 1rem
$spacers ?= 0, $spacer * .25, $spacer * .5, $spacer, $spacer * 1.5, $spacer * 3

for n in (0 .. 5)
    .ml-{n}
        margin-left: $spacers[n] !important

    .mr-{n}
        margin-right: $spacers[n] !important

    .mx-{n}
        @extend .ml-{n}, .mr-{n}

    .ml-n{n}
        margin-left: - $spacers[n] !important

    .mr-n{n}
        margin-right: - $spacers[n] !important

    .mx-n{n}
        @extend .ml-n{n}, .mr-n{n}

    .mt-{n}
        margin-top: $spacers[n] !important

    .mb-{n}
        margin-bottom: $spacers[n] !important

    .my-{n}
        @extend .mt-{n}, .mb-{n}

    .mt-n{n}
        margin-top: - $spacers[n] !important

    .mb-n{n}
        margin-bottom: - $spacers[n] !important

    .my-n{n}
        @extend .mt-n{n}, .mb-n{n}

    .pl-{n}
        padding-left: $spacers[n] !important

    .pr-{n}
        padding-right: $spacers[n] !important

    .px-{n}
        @extend .pl-{n}, .pr-{n}

    .pl-n{n}
        padding-left: - $spacers[n] !important

    .pr-n{n}
        padding-right: - $spacers[n] !important

    .px-n{n}
        @extend .pl-n{n}, .pr-n{n}

    .pt-{n}
        padding-top: $spacers[n] !important

    .pb-{n}
        padding-bottom: $spacers[n] !important

    .py-{n}
        @extend .pt-{n}, .pb-{n}

    .pt-n{n}
        padding-top: - $spacers[n] !important

    .pb-n{n}
        padding-bottom: - $spacers[n] !important

    .py-n{n}
        @extend .pt-n{n}, .pb-n{n}

.ml-auto
    margin-left: auto !important

.mr-auto
    margin-right: auto !important

.mx-auto
    @extend .ml-auto, .mr-auto

.mt-auto
    margin-top: auto !important

.mb-auto
    margin-bottom: auto !important

.my-auto
    @extend .mt-auto, .mb-auto

.pl-auto
    margin-left: auto !important

.pr-auto
    margin-right: auto !important

.px-auto
    @extend .pl-auto, .pr-auto

.pt-auto
    margin-top: auto !important

.pb-auto
    margin-bottom: auto !important

.py-auto
    @extend .pt-auto, .pb-auto

/* ---------------------------------
 *           Flex helpers
 * --------------------------------- */
for n in (0 .. 5)
    .order-{n}
        order: n !important

.justify-content-start
    justify-content: start !important

.justify-content-center
    justify-content: center !important

.flex-shrink-1
    flex-shrink: 1 !important

/* ---------------------------------
 *           Color helpers
 * --------------------------------- */
.link-muted
    color: inherit

    &:hover
        color: $primary !important

/* ---------------------------------
 *          Image helpers
 * --------------------------------- */
.image
    &.is-7by3
        padding-top: 42.8%

        img
            bottom: 0
            left: 0
            position: absolute
            right: 0
            top: 0

    .avatar
        height: 100%
        object-fit: cover

    .fill
        object-fit: cover
        width: 100% !important
        height: 100% !important

================================================
FILE: include/style/navbar.styl
================================================
/* ---------------------------------
 *           Top Navigation
 * --------------------------------- */
$navbar-item-padding-v ?= 1.25rem
$navbar-item-padding-h ?= .75rem
$navbar-item-margin-v ?= 0
$navbar-item-margin-h ?= 0

.navbar-main
    box-shadow: $shadow

    .navbar-container
        overflow-x: auto

    .navbar-menu, .navbar-start, .navbar-end
        align-items: stretch
        display: flex
        padding: 0
        flex-shrink: 0

    .navbar-menu
        flex-grow: 1
        flex-shrink: 0
        overflow-x: auto

    .navbar-start
        justify-content: flex-start
        margin-right: auto

    .navbar-end
        justify-content: flex-end
        margin-left: auto

    .navbar-item
        display: flex
        align-items: center
        padding: $navbar-item-padding-v $navbar-item-padding-h
        margin: $navbar-item-margin-v $navbar-item-margin-h

        &.is-active
            background-color: transparent

    +until($navbar-breakpoint)
        .navbar-menu
            justify-content: center
            box-shadow: none

        .navbar-start
            margin-right: 0

        .navbar-end
            margin-left: 0

.navbar-logo
    img
        max-height: $logo-height

@media screen and (min-width: $desktop)
    .navbar > .container .navbar-menu, .container > .navbar .navbar-menu
        margin-right: 0rem


================================================
FILE: include/style/pagination.styl
================================================
/* ---------------------------------
 *  Pagination and Post Navigation
 * --------------------------------- */
$pagination-box-shadow ?= $card-shadow
$pagination-background-color ?= $button-background-color
$post-navigation-fg ?= $grey

.pagination
    @extend .pagination.is-centered
    margin-top: 1.5rem

    .pagination-link,
    .pagination-ellipsis,
    .pagination-previous,
    .pagination-next
        a
            color: $pagination-color
    .pagination-link,
    .pagination-previous,
    .pagination-next
        border: none
        background: $pagination-background-color
        box-shadow: $pagination-box-shadow
    .pagination-link.is-current
        background: $pagination-current-background-color

.post-navigation
    color: $post-navigation-fg
    flex-wrap: wrap
    justify-content: space-around
    .level-item
        margin-bottom: 0


================================================
FILE: include/style/plugin.styl
================================================
/* ---------------------------------
 *        Back to Top Button
 * --------------------------------- */
#back-to-top
    position: fixed
    opacity: 0
    outline: none
    padding: 8px 0
    line-height: 24px
    border-radius: $card-radius
    transform: translateY(120px)
    transition: .4s ease opacity, .4s ease width, .4s ease transform, .4s ease border-radius

    &.is-rounded
        border-radius: 50%

    &.fade-in
        opacity: 1

    &.rise-up
        transform: translateY(0)

/* ---------------------------------
 *          Gallery Plugin
 * --------------------------------- */
.gallery-item
    .caption
        color: $grey

/* ---------------------------------
 *      Page Loading Progressbar
 * --------------------------------- */
.pace
    user-select: none
    pointer-events: none

    .pace-progress
        top: 0
        right: 100%
        width: 100%
        height: 2px
        z-index: 2000
        position: fixed
        background: $primary

.pace-inactive
    display: none

/* ---------------------------------
 *       Fix FontAwesome Icons
 * --------------------------------- */
.fa, .fab, .fal, .far, .fas
    line-height: inherit

/* ---------------------------------
 *       MathJax and KaTeX
 * --------------------------------- */
.MathJax, .MathJax_Display, .MJXc-display, .MathJax_SVG_Display, .katex-display
    overflow-x: auto
    overflow-y: hidden

.katex
    white-space: nowrap

.katex-display
    margin-top: -1em !important

.katex-html
    padding-top: 1em

    .tag
        align-items: unset
        background-color: unset
        border-radius: unset
        color: unset
        display: unset
        font-size: unset
        height: unset
        justify-content: unset
        line-height: unset
        padding-left: unset
        padding-right: unset
        white-space: unset

/* ---------------------------------
 *         Cookie Consent
 * --------------------------------- */
.cc-window, .cc-revoke
    font-size: 1.1rem !important
    font-family: $family-sans-serif !important

.cc-window
    color: $text !important
    background-color: $scheme-main !important

    &.cc-floating
        border-radius: $card-radius
        box-shadow: $card-shadow

    &.cc-banner
        background-color: darken($scheme-main, 2.5%) !important

    &.cc-theme-block, &.cc-theme-classic
        .cc-compliance > .cc-btn
            border-radius: $radius-rounded

    .cc-compliance > .cc-btn
        font-weight: 400
        border: none
        color: $primary-invert
        background-color: $primary

        &:hover, &:focus
            background-color: darken($primary, 2.5%)

        &.cc-deny
            &:hover
                color: $primary
                text-decoration: none

.cc-revoke
    padding: .5rem 1rem !important
    color: $primary-invert !important
    background-color: $primary !important

    &:hover
        text-decoration: none !important
        background-color: darken($primary, 2.5%)


================================================
FILE: include/style/responsive.styl
================================================
/* ---------------------------------
 *         Responsive Layout
 * --------------------------------- */
+widescreen()
    .is-1-column .container, .is-2-column .container
        max-width: $desktop - 2 * $gap
        width: $desktop - 2 * $gap

+fullhd()
    .is-2-column .container
        max-width: $widescreen - 2 * $gap
        width: $widescreen - 2 * $gap

    .is-1-column .container
        max-width: $desktop - 2 * $gap
        width: $desktop - 2 * $gap

+tablet()
    .is-sticky
        position: -webkit-sticky
        position: sticky
        top: 1.5rem
        z-index: 99

    .column-main, .column-left, .column-right, .column-right-shadow
        &.is-sticky
            top: .75rem
            align-self: flex-start

+mobile()
    .section
        padding: 1.5rem 1rem


================================================
FILE: include/style/search.styl
================================================
/* ---------------------------------
 *           Search Box
 * --------------------------------- */
// container sizes
$searchbox-container-width ?= 540px
$searchbox-container-margin ?= 100px
$searchbox-breakpoint-width ?= 559px
$searchbox-breakpoint-height ?= 479px
// overlay and container styles
$searchbox-box-shadow ?= $card-shadow
$searchbox-border-radius ?= $radius
$searchbox-bg-overlay ?= $modal-background-background-color
$searchbox-bg-container ?= $white-ter
$searchbox-border ?= $border
// header styles
$searchbox-bg-input ?= $white
$searchbox-bg-close-hover ?= $searchbox-bg-container
$searchbox-bg-close-active ?= $grey-lighter
// body styles
$searchbox-fg-result-header ?= $grey-light
$searchbox-fg-result-item-secondary ?= $grey-light
$searchbox-bg-result-item-hover ?= $searchbox-bg-input
$searchbox-fg-result-item-active ?= findColorInvert($primary)
$searchbox-bg-result-item-active ?= $primary
$searchbox-bg-result-item-highlight ?= $yellow
// footer styles
$searchbox-bg-pagination-item ?= $searchbox-bg-input
$searchbox-bg-pagination-item-hover ?= $searchbox-bg-container
$searchbox-fg-pagination-item-active ?= findColorInvert($primary)
$searchbox-bg-pagination-item-active ?= $primary
$searchbox-bg-pagination-item-disabled ?= $searchbox-bg-container

.searchbox
    display: none
    top: 0
    left: 0
    width: 100%
    height: 100%
    z-index: 100
    font-size: 1rem
    line-height: 0
    background: $searchbox-bg-overlay

    &.show
        display: flex

    a, a:hover
        color: inherit
        text-decoration: none

    input
        font-size: 1rem
        border: none
        outline: none
        box-shadow: none
        border-radius: 0

    &, .searchbox-container
        position: fixed
        align-items: center
        flex-direction: column
        line-height: 1.25em

    .searchbox-container
        z-index: 101
        display: flex
        overflow: hidden
        box-shadow: $searchbox-box-shadow
        border-radius: $searchbox-border-radius
        background-color: $searchbox-bg-container
        width: $searchbox-container-width
        top: $searchbox-container-margin
        bottom: $searchbox-container-margin

    .searchbox-header, .searchbox-body, .searchbox-footer
        width: 100%

    .searchbox-header
        display: flex
        flex-direction: row
        line-height: 1.5em
        font-weight: normal
        background-color: $searchbox-bg-input
        // fix Chrome 71 height issue
        // https://github.com/ppoffice/hexo-theme-icarus/issues/719
        min-height: 3rem

    .searchbox-input-container
        display: flex
        flex-grow: 1

    .searchbox-input
        flex-grow: 1
        color: inherit
        box-sizing: border-box
        padding: .75em 0 .75em 1.25em
        background: $searchbox-bg-input

    .searchbox-close
        display: inline-block
        font-size: 1.5em
        padding: .5em .75em
        cursor: pointer

        &:hover
            background: $searchbox-bg-close-hover

        &:active
            background: $searchbox-bg-close-active

    .searchbox-body
        flex-grow: 1
        overflow-y: auto
        border-top: 1px solid $searchbox-border

    .searchbox-result-section header, .searchbox-result-item
        padding: .75em 1em

    .searchbox-result-section
        border-bottom: 1px solid $searchbox-border

        header
            color: $searchbox-fg-result-header

    .searchbox-result-item
        display: flex
        flex-direction: row

        &:not(.disabled):not(.active):not(:active):hover
            background-color: $searchbox-bg-result-item-hover

        &:active, &.active
            color: $searchbox-fg-result-item-active
            background-color: $searchbox-bg-result-item-active

        em
            font-style: normal
            background: $searchbox-bg-result-item-highlight

    .searchbox-result-icon
        margin-right: 1em

    .searchbox-result-content
        overflow: hidden

    .searchbox-result-title, .searchbox-result-preview
        display: block
        overflow: hidden
        white-space: nowrap
        text-overflow: ellipsis

    .searchbox-result-title-secondary
        color: $searchbox-fg-result-item-secondary

    .searchbox-result-preview
        margin-top: .25em

    .searchbox-result-item:not(:active):not(.active)
        .searchbox-result-preview
            color: $searchbox-fg-result-item-secondary

    .searchbox-footer
        padding: .5em 1em

    .searchbox-pagination
        margin: 0
        padding: 0
        list-style: none
        text-align: center

        .searchbox-pagination-item
            margin: 0 .25rem

        .searchbox-pagination-item, .searchbox-pagination-link
            display: inline-block

        .searchbox-pagination-link
            overflow: hidden
            padding: .5em .8em
            box-shadow: $searchbox-box-shadow
            border-radius: $searchbox-border-radius
            background-color: $searchbox-bg-pagination-item

        .searchbox-pagination-item.active
            .searchbox-pagination-link
                color: $searchbox-fg-pagination-item-active
                background-color: $searchbox-bg-pagination-item-active

        .searchbox-pagination-item.disabled
            .searchbox-pagination-link
                cursor: not-allowed
                background-color: $searchbox-bg-pagination-item-disabled

        .searchbox-pagination-item:not(.active):not(.disabled)
            .searchbox-pagination-link:hover
                background-color: $searchbox-bg-pagination-item-hover

@media screen and (max-width: $searchbox-breakpoint-width), screen and (max-height: $searchbox-breakpoint-height)
    .searchbox .searchbox-container
        top: 0
        left: 0
        width: 100%
        height: 100%
        border-radius: 0


================================================
FILE: include/style/timeline.styl
================================================
/* ---------------------------------
 *          Archive Timeline
 * --------------------------------- */
$timeline-fg-line ?= $grey-lighter
$timeline-bg-line ?= $card-background-color

.timeline
    margin-left: 1rem
    padding: 1rem 0 0 1.5rem
    border-left: 1px solid $timeline-fg-line

    .media
        position: relative

        &:before, &:last-child:after
            content: ''
            display: block
            position: absolute
            left: calc(-.375rem - 1.5rem - .25px)

        &:before
            width: .75rem
            height: .75rem
            top: calc(1rem + 1.5 * .85rem / 2 - .75rem / 2)
            background: $timeline-fg-line
            border-radius: 50%

        &:first-child:before
            top: calc(1.5 * .85rem / 2 - .75rem / 2)

        &:last-child:after
            width: .75rem
            top: calc(1rem + 1.5 * .85rem / 2 + .75rem / 2)
            bottom: 0
            background: $timeline-bg-line

        &:first-child:last-child:after
            top: calc(1.5 * .85rem / 2 + .75rem / 2)


================================================
FILE: include/style/widget.styl
================================================
.widget
    .menu-list
        li
            ul
                margin-right: 0

        .level
            margin-bottom: 0

            .level-left, .level-right, .level-item
                flex-shrink: 1

            .level-left, .level-right
                align-items: flex-start

        .tag
            background: $light-grey
            color: $white-invert

    .tags
        .tag:first-child
            background: $primary
            color: $primary-invert

        .tag:last-child
            background: $light-grey
            color: $white-invert

.level.is-multiline
    flex-wrap: wrap

/* ---------------------------------
 *      Table of Content Widget
 * --------------------------------- */
+mobile()
    .widget.card#toc
        display: none
        position: fixed
        margin: 1rem
        left: 0
        right: 0
        bottom: 0
        z-index: 100

        .card-content
            padding: 0

        .menu
            padding: 1.5rem
            max-height: calc(100vh - 2rem)
            overflow-y: auto

    #toc-mask
        display: none
        position: fixed
        top: 0
        left: 0
        right: 0
        bottom: 0
        z-index: 99
        background: rgba(0, 0, 0, .7)

    .widget.card#toc, #toc-mask
        &.is-active
            display: block

================================================
FILE: include/util/console.js
================================================
let chalk;
try {
    chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require
} catch (e) { }

module.exports = new Proxy({}, {
    get(obj, prop) {
        if (chalk) {
            return chalk[prop];
        }
        return function() {
            return arguments.length === 1 ? arguments[0] : arguments;
        };
    }
});


================================================
FILE: languages/de.yml
================================================
common:
    archive:
        one: 'Archiv'
        other: 'Archive'
    category:
        one: 'Kategorie'
        other: 'Kategorien'
    tag:
        one: 'Tag'
        other: 'Tags'
    post:
        one: 'Seite'
        other: 'Seiten'
    page:
        one: 'Page'
        other: 'Pages'
    prev: 'Zurück'
    next: 'Weiter'
widget:
    follow: 'Folgen'
    recents: 'Letzte Einträge'
    links: 'Links'
    catalogue: 'Katalog'
    subscribe_email: 'Abonnieren Sie Updates'
    subscribe: 'Abonnieren'
    adsense: 'Werbung'
    followit: 'follow.it'
article:
    created_at: 'Gepostet vor&nbsp;%s'
    updated_at: 'Aktualisiert vor&nbsp;%s'
    more: 'Mehr lesen'
    comments: 'Kommentare'
    read_time: '%s lesen'
    word_count:
        one: 'Über %d Wort'
        other: 'Über %d Wörter'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Gefällt Ihnen der Artikel? Unterstützen Sie den Autor mit'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Kauf mir einen Kaffee'
plugin:
    backtotop: 'Zurück nach oben'
    visit_count: '%s&nbsp;Besuche'
    visitor_count: 'Von %s Nutzern besucht'
    cookie_consent:
      message: Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern.
      dismiss: Verstanden!
      allow: Cookies zulassen
      deny: Ablehnen
      link: Mehr erfahren
      policy: Cookie-Richtlinie
search:
    search: 'Suche'
    hint: 'Tippen Sie etwas...'
    no_result: 'Keine Ergebnisse für'
    untitled: '(Ohne Titel)'
    empty_preview: '(Keine Vorschau)'


================================================
FILE: languages/en.yml
================================================
common:
    archive:
        one: 'Archive'
        other: 'Archives'
    category:
        one: 'Category'
        other: 'Categories'
    tag:
        one: 'Tag'
        other: 'Tags'
    post:
        one: 'Post'
        other: 'Posts'
    page:
        one: 'Page'
        other: 'Pages'
    prev: 'Previous'
    next: 'Next'
widget:
    follow: 'Follow'
    recents: 'Recents'
    links: 'Links'
    catalogue: 'Catalogue'
    subscribe_email: 'Subscribe for updates'
    subscribe: 'Subscribe'
    adsense: 'Advertisement'
    followit: 'follow.it'
article:
    created_at: 'Posted&nbsp;%s'
    updated_at: 'Updated&nbsp;%s'
    more: 'Read more'
    comments: 'Comments'
    read_time: '%s read'
    word_count:
        one: 'About %d word'
        other: 'About %d words'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Like this article? Support the author with'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Buy me a coffee'
plugin:
    backtotop: 'Back to top'
    visit_count: '%s&nbsp;visits'
    visitor_count: 'Visited by %s users'
    cookie_consent:
      message: This website uses cookies to improve your experience.
      dismiss: Got it!
      allow: Allow cookies
      deny: Decline
      link: Learn more
      policy: Cookie Policy
search:
    search: 'Search'
    hint: 'Type something...'
    no_result: 'No results for'
    untitled: '(Untitled)'
    empty_preview: '(No preview)'


================================================
FILE: languages/es.yml
================================================
#By SrWoOoW
common:
    archive:
        one: 'Archivo'
        other: 'Archivos'
    category:
        one: 'Categoría'
        other: 'Categorías'
    tag:
        one: 'Etiqueta'
        other: 'Etiquetas'
    post:
        one: 'Entrada'
        other: 'Entradas'
    page:
        one: 'Página'
        other: 'Páginas'
    prev: 'Anterior'
    next: 'Siguiente'
widget:
    follow: 'SEGUIR'
    recents: 'Recientes'
    links: 'Enlaces'
    catalogue: 'Catálogo'
    subscribe_email: 'Suscríbete para recibir actualizaciones'
    subscribe: 'Suscribir'
    adsense: 'Anuncio'
    followit: 'follow.it'
article:
    created_at: 'Publicado hace&nbsp;%s'
    updated_at: 'Actualizado hace&nbsp;%s'
    more: 'Leer más'
    comments: 'Comentarios'
    read_time: '%s de lectura'
    word_count:
        one: 'Aproximadamente %d palabra'
        other: 'Aproximadamente %d palabras'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: '¿Te gusta este artículo? Apoya al autor con'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Cómprame un café'
plugin:
    backtotop: 'Volver arriba'
    visit_count: '%s&nbsp;visitas'
    visitor_count: 'Visitado por %s usuarios'
    cookie_consent:
      message: Este sitio web utiliza cookies para mejorar su experiencia.
      dismiss: ¡Entendido!
      allow: Permitir cookies
      deny: Descenso
      link: Aprende más
      policy: Política de cookies
search:
    search: 'Buscar'
    hint: 'Teclea algo...'
    no_result: 'No hay resultados para'
    untitled: '(Sin título)'
    empty_preview: '(Sin vista previa)'


================================================
FILE: languages/fr.yml
================================================
common:
    archive:
        one: 'Archive'
        other: 'Archives'
    category:
        one: 'Catégorie'
        other: 'Catégories'
    tag:
        one: 'Tag'
        other: 'Tags'
    post:
        one: 'Article'
        other: 'Articles'
    page:
        one: 'Page'
        other: 'Pages'
    prev: 'Préc'
    next: 'Suiv'
widget:
    follow: 'Suivre'
    recents: 'Récents'
    links: 'Liens'
    catalogue: 'Catalogue'
    subscribe_email: 'Abonnez-vous aux mises à jour'
    subscribe: 'Abonnez-vous'
    adsense: 'Publicités'
    followit: 'follow.it'
article:
    created_at: 'Publié il y a&nbsp;%s'
    updated_at: 'Mis à jour il y a&nbsp;%s'
    more: 'Lire la suite'
    comments: 'Commentaires'
    read_time: '%s de lecture'
    word_count:
        one: 'Environ %d mot'
        other: 'Environ %d mots'
    licensing:
        author: 'Auteur'
        created_at: 'Posté le'
        updated_at: 'Mis à jour le'
        licensed_under: 'Licencié sous'
donate:
    title: "Vous aimez cet article? Soutenez l'auteur avec"
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Achetez-moi un café'
plugin:
    backtotop: 'Retour en haut'
    visit_count: '%s&nbsp;visites'
    visitor_count: 'Visité par %s utilisateurs'
    cookie_consent:
      message: 'Ce site Web utilise des cookies pour améliorer votre expérience.'
      dismiss: "C'est bon"
      allow: 'Autoriser les cookies'
      deny: 'Refuser'
      link: 'En savoir plus'
      policy: 'Politique relative aux cookies'
search:
    search: 'Rechercher'
    hint: 'Ecrivez quelque chose...'
    no_result: 'Aucun résultat pour'
    untitled: '(Sans titre)'
    empty_preview: '(Pas de prévisualisation)'


================================================
FILE: languages/id.yml
================================================
common:
    archive:
        one: 'Arsip'
        other: 'Arsip'
    category:
        one: 'Kategori'
        other: 'Kategori'
    tag:
        one: 'Tag'
        other: 'Tag'
    post:
        one: 'Artikel'
        other: 'Artikel'
    page:
        one: 'Halaman'
        other: 'Halaman'
    prev: 'Sebelumnya'
    next: 'Berikutnya'
widget:
    follow: 'IKUTI'
    recents: 'Terbaru'
    links: 'Tautan'
    catalogue: 'Katalog'
    subscribe_email: 'Berlangganan untuk pembaruan'
    subscribe: 'Berlangganan'
    adsense: 'Iklan'
    followit: 'follow.it'
article:
    created_at: 'Diposting&nbsp;%s'
    updated_at: 'Diperbarui&nbsp;%s'
    more: 'Selengkapnya'
    comments: 'Komentar'
    read_time: '%s membaca'
    word_count:
        one: 'Sekitar %d kata'
        other: 'Sekitar %d kata'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Suka dengan artikel ini? Bantu penulis dengan donasi melalui'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Belikan aku kopi'
plugin:
    backtotop: 'Kembali ke atas'
    visit_count: '%s&nbsp;kunjungan'
    visitor_count: 'Dikunjungi oleh %s pengguna'
    cookie_consent:
      message: Situs web ini menggunakan cookie untuk meningkatkan pengalaman Anda.
      dismiss: Mengerti!
      allow: Izinkan cookie
      deny: Menolak
      link: Belajarlah lagi
      policy: Kebijakan Cookie
search:
    search: 'Pencarian'
    hint: 'Tulis Sesuatu..'
    no_result: 'Tidak ada hasil untuk'
    untitled: '(Tanpa judul)'
    empty_preview: '(Tidak ada preview)'


================================================
FILE: languages/it.yml
================================================
common:
    archive:
        one: 'Archivio'
        other: 'Archivi'
    category:
        one: 'Categoria'
        other: 'Categorie'
    tag:
        one: 'Tag'
        other: 'Tag'
    post:
        one: 'Articolo'
        other: 'Articoli'
    page:
        one: 'Pagina'
        other: 'Pagine'
    prev: 'Precedente'
    next: 'Successivo'
widget:
    follow: 'Segui'
    recents: 'Recenti'
    links: 'Collegamenti'
    catalogue: 'Catalogo'
    subscribe_email: 'Iscriviti per aggiornamenti'
    subscribe: 'Iscriviti'
    adsense: 'Pubblicità'
    followit: 'follow.it'
article:
    created_at: 'Pubblicato il&nbsp;%s'
    updated_at: 'Aggiornato il&nbsp;%s'
    more: 'Di più'
    comments: 'Commenti'
    read_time: '%s di lettura'
    word_count:
        one: 'Circa %d parola'
        other: 'Circa %d parole'
    licensing:
        author: 'Autore'
        created_at: 'Pubblicato il'
        updated_at: 'Aggiornato il'
        licensed_under: 'Licenza'
donate:
    title: "Ti è piaciuto questo articolo? Supporta l'autore con"
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Buy me a coffee'
plugin:
    backtotop: 'Torna su'
    visit_count: '%s&nbsp;visite'
    visitor_count: 'Visto da %s usenti'
    cookie_consent:
      message: Questo sito usa i cookie per migliorare la tua esperienza.
      dismiss: "D'accordo!"
      allow: Accetta i cookie
      deny: Rifiuta
      link: Più informazioni
      policy: Politica dei cookie
search:
    search: 'Cerca'
    hint: 'Digita qualcosa...'
    no_result: 'Nessun risultato per'
    untitled: '(Senza titolo)'
    empty_preview: '(Senza anteprima)'


================================================
FILE: languages/ja.yml
================================================
common:
    archive:
        one: 'アーカイブ'
        other: 'アーカイブ'
    category:
        one: 'カテゴリ'
        other: 'カテゴリ'
    tag:
        one: 'タグ'
        other: 'タグ'
    post:
        one: '投稿'
        other: '投稿'
    page:
        one: 'ページ'
        other: 'ページ'
    prev: '前'
    next: '次'
widget:
    follow: 'フォローする'
    recents: '最近の記事'
    links: 'リンク'
    catalogue: 'カタログ'
    subscribe_email: '更新を購読する'
    subscribe: '購読する'
    adsense: '広告'
    followit: 'follow.it'
article:
    created_at: '%sに投稿'
    updated_at: '%sに更新'
    more: '続きを読む'
    comments: 'コメント'
    read_time: '%sで読む'
    word_count:
        one: '約%d語'
        other: '約%d語'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'この記事は気に入りましたか? 著者をサポートする'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'コーヒーを買って'
plugin:
    backtotop: 'トップに戻る'
    visit_count: '%s回の訪問'
    visitor_count: '%s人のユーザーがアクセス'
    cookie_consent:
      message: このウェブサイトはあなたの経験を改善するためにCookieを使用しています。
      dismiss: 了解しました
      allow: Cookiesを許可する
      deny: 拒否する
      link: もっと詳しく知る
      policy: Cookieポリシー
search:
    search: '検索'
    hint: '何かを入力してください...'
    no_result: 'の結果はありません'
    untitled: '(無題)'
    empty_preview: '(プレビューなし)'


================================================
FILE: languages/ko.yml
================================================
common:
    archive:
        one: '아카이브'
        other: '아카이브'
    category:
        one: '카테고리'
        other: '카테고리'
    tag:
        one: '태그'
        other: '태그'
    post:
        one: '포스트'
        other: '포스트'
    page:
        one: '페이지'
        other: '페이지'
    prev: '이전'
    next: '다음'
widget:
    follow: '팔로우'
    recents: '최근 글'
    links: '링크'
    catalogue: '카탈로그'
    subscribe_email: '업데이트 소식 받기'
    subscribe: '구독'
    adsense: '광고'
    followit: 'follow.it'
article:
    created_at: '%s&nbsp;게시 됨'
    updated_at: '%s&nbsp;업데이트 됨'
    more: '자세히 보기'
    comments: '댓글'
    read_time: '%s안에 읽기'
    word_count:
        one: '약 %d 단어'
        other: '약 %d 단어'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: '이 글이 마음에 드시나요? 다음을 통해 후원하실 수 있습니다: '
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: '커피 한 잔 사주기'
plugin:
    backtotop: '맨 위로'
    visit_count: '%s회 방문'
    visitor_count: '%s명의 사용자가 방문 함'
    cookie_consent:
        message: 이 웹 사이트는 귀하의 경험을 향상시키기 위해 Cookie를 사용합니다.
        dismiss: 무시
        allow: 허용
        deny: 거부
        link: 더 알아보기
        policy: Cookie 정책
search:
    search: '검색'
    hint: '입력 하세요...'
    no_result: '에 대한 결과 없음'
    untitled: '(제목 없음)'
    empty_preview: '(미리보기 없음)'


================================================
FILE: languages/pl.yml
================================================
common:
    archive:
        one: 'Archiwum'
        other: 'Archiwum'
    category:
        one: 'Kategoria'
        other: 'Kategorie'
    tag:
        one: 'Tag'
        other: 'Tagi'
    post:
        one: 'Artykuł'
        other: 'Artykuły'
    page:
        one: 'Strona'
        other: 'Strony'
    prev: 'Poprzedni'
    next: 'Następny'
widget:
    follow: 'SUBSKRYBUJ'
    recents: 'Najnowsze wpisy'
    links: 'Linki'
    catalogue: 'Spis treści'
    subscribe_email: 'Zapisz się, aby otrzymywać aktualizacje'
    subscribe: 'Subskrybuj'
    adsense: 'Reklama'
    followit: 'follow.it'
article:
    created_at: 'Opublikowano&nbsp;%s'
    updated_at: 'Zaktualizowano&nbsp;%s'
    more: 'Czytaj dalej'
    comments: 'Komentarze'
    read_time: '%s czytania'
    word_count:
        one: 'Około %d słowa'
        other: 'Około %d słów'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Podoba Ci się ten artykuł? Wesprzyj autora za pomocą'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Kup mi kawę'
plugin:
    backtotop: 'Powrót do góry'
    visit_count: '%s&nbsp;wizyty'
    visitor_count: 'Odwiedzone przez %s użytkowników'
    cookie_consent:
      message: Ta strona korzysta z plików cookie, aby poprawić Twoje doświadczenia.
      dismiss: Rozumiem!
      allow: Zezwól na pliki cookie
      deny: Odrzucać
      link: Ucz się więcej
      policy: Polityka Cookie
search:
    search: 'szukaj'
    hint: 'Wpisz coś...'
    no_result: 'Brak wyników dla'
    untitled: '(Bez tytułu)'
    empty_preview: '(Brak podglądu)'


================================================
FILE: languages/pt-BR.yml
================================================
common:
    archive:
        one: 'Arquivo'
        other: 'Arquivos'
    category:
        one: 'Categoria'
        other: 'Categorias'
    tag:
        one: 'Tag'
        other: 'Tags'
    post:
        one: 'Artigo'
        other: 'Artigos'
    page:
        one: 'Página'
        other: 'Páginas'
    prev: 'Anterior'
    next: 'Próximo'
widget:
    follow: 'Seguir'
    recents: 'Recentes'
    links: 'Links'
    catalogue: 'Catálogo'
    subscribe_email: 'Subscrição de atualizações'
    subscribe: 'Se inscrever'
    adsense: 'Anúncio'
    followit: 'follow.it'
article:
    created_at: 'Postado&nbsp;%s'
    updated_at: 'Atualizado&nbsp;%s'
    more: 'Ler Mais'
    comments: 'Comentarios'
    read_time: '%s lidos'
    word_count:
        one: 'Cerca de %d palavra'
        other: 'Cerca de %d palavras'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Gostou deste artigo? Apoie o autor com'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Me compra um café'
plugin:
    backtotop: 'De volta ao topo'
    visit_count: '%s&nbsp;visitas'
    visitor_count: 'Visitado por %s usuários'
    cookie_consent:
      message: Este site usa cookies para melhorar sua experiência.
      dismiss: Entendi!
      allow: Permitir cookies
      deny: Declínio
      link: Saber mais
      policy: Política de Cookies
search:
    search: 'Procurar'
    hint: 'Digite alguma coisa...'
    no_result: 'Sem resultados para'
    untitled: '(Sem título)'
    empty_preview: '(Não há visualização)'


================================================
FILE: languages/ru.yml
================================================
common:
    archive:
        one: 'архив'
        other: 'архивы'
    category:
        one: 'категории'
        other: 'категории'
    tag:
        one: 'тег'
        other: 'теги'
    post:
        one: 'пост'
        other: 'посты'
    page:
        one: 'страница'
        other: 'страницы'
    prev: 'Назад'
    next: 'Далее'
widget:
    follow: 'Подписаться'
    recents: 'недавние'
    links: 'ссылки'
    catalogue: 'Каталог'
    subscribe_email: 'Подпишитесь на обновления'
    subscribe: 'Подписывайся'
    adsense: 'Рекламное объявление'
    followit: 'follow.it'
article:
    created_at: 'Опубликовано&nbsp;%s'
    updated_at: 'Обновлено&nbsp;%s'
    more: 'Читать дальше'
    comments: 'Комментарии'
    read_time: '%s на чтение'
    word_count:
        one: 'Около %d слова'
        other: 'Примерно %d слова'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Понравилась эта статья? Поддержите автора'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Купи мне кофе'
plugin:
    backtotop: 'Вернуться наверх'
    visit_count: '%s&nbsp;посещения'
    visitor_count: 'Посетили %s пользователя'
    cookie_consent:
      message: Этот веб-сайт использует файлы cookie для улучшения вашего опыта.
      dismiss: Понял!
      allow: Разрешить cookies
      deny: Отказаться
      link: Учить больше
      policy: Политика Cookie
search:
    search: 'Поиск'
    hint: 'Введите что-нибудь...'
    no_result: 'Нет результатов по запросу'
    untitled: '(Без названия)'
    empty_preview: '(Нет предварительного просмотра)'


================================================
FILE: languages/sv.yml
================================================
common:
    archive:
        one: 'Arkiv'
        other: 'Arkiv'
    category:
        one: 'Kategori'
        other: 'Kategorier'
    tag:
        one: 'Etikett'
        other: 'Etiketter'
    post:
        one: 'Inlägg'
        other: 'Inlägg'
    page:
        one: 'Sida'
        other: 'Sidor'
    prev: 'Föregående'
    next: 'Nästa'
widget:
    follow: 'Följ'
    recents: 'Senaste'
    links: 'Länkar'
    catalogue: 'Katalog'
    subscribe_email: 'Prenumerera för uppdateringar'
    subscribe: 'Prenumerera'
    adsense: 'Marknadsföring'
    followit: 'follow.it'
article:
    created_at: 'Publicerad&nbsp;%s'
    updated_at: 'Uppdaterad&nbsp;%s'
    more: 'Läs mer'
    comments: 'Kommentarer'
    read_time: '%s lästid'
    word_count:
        one: 'Cirka %d ord'
        other: 'Cirka %d ord'
    licensing:
        author: 'Författare'
        created_at: 'Publicerad'
        updated_at: 'Uppdaterad'
        licensed_under: 'Licensierad under'
donate:
    title: 'Tycker du om den här artikeln? Stöd författaren genom'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Köp mig en kaffe'
plugin:
    backtotop: 'Tillbaka till början'
    visit_count: '%s&nbsp;besök'
    visitor_count: 'Besökt av %s användare'
    cookie_consent:
      message: Den här hemsidan använder kakor för att förbättra funktionen.
      dismiss: Jag förstår!
      allow: Tillåt kakor
      deny: Avböj kakor
      link: Lär mer
      policy: Kakpolicy
search:
    search: 'Sök'
    hint: 'Skriv någonting...'
    no_result: 'Inga sökresultat för'
    untitled: '(Utan titel)'
    empty_preview: '(Ingen förhandsvisning)'


================================================
FILE: languages/tk.yml
================================================
common:
    archive:
        one: 'Arhiw'
        other: 'Arhiwler'
    category:
        one: 'Bölüm'
        other: 'Bölümler'
    tag:
        one: 'Teg'
        other: 'Tegler'
    post:
        one: 'Post'
        other: 'Postlar'
    page:
        one: 'Sahypa'
        other: 'Sahypalar'
    prev: 'Öňki'
    next: 'Indiki'
widget:
    follow: 'Abuna bol'
    recents: 'Täze habarlar'
    links: 'Linkler'
    catalogue: 'Katalog'
    subscribe_email: 'Täzelikler üçin ýazyl'
    subscribe: 'Ýazyl'
    adsense: 'Mahabat'
    followit: 'follow.it'
article:
    created_at: 'Paýlaşyldy&nbsp;%s'
    updated_at: 'Üýtgedildi&nbsp;%s'
    more: 'Dowamy...'
    comments: 'Kommentariýa'
    read_time: '%s okaldy'
    word_count:
        one: 'Ortaça %d söz'
        other: 'Ortaça %d söz'
    licensing:
        author: 'Awtor'
        created_at: 'Paýlaşdy'
        updated_at: 'Üýtgetdi'
        licensed_under: 'Resmileşdirilen'
donate:
    title: 'Haladynmy? Awtory gollaň'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Buy me a coffee'
plugin:
    backtotop: 'Ýokaryk'
    visit_count: '%s&nbsp;görüldi'
    visitor_count: '%s adam gördi'
    cookie_consent:
      message: Bu web saýt siziň üçin kuki ulanýar.
      dismiss: Düşündim!
      allow: Kukini kabul et!
      deny: Närazylyk bildir
      link: Dowamy...
      policy: Kuki syýasaty
search:
    search: 'Gözle'
    hint: 'Birzatlar ýazyň...'
    no_result: 'Tapylmady'
    untitled: 'Atlandyrylmadyk'
    empty_preview: 'Boş'


================================================
FILE: languages/tr.yml
================================================
common:
    archive:
        one: 'Arşiv'
        other: 'Arşivler'
    category:
        one: 'Kategori'
        other: 'Kategoriler'
    tag:
        one: 'Etiket'
        other: 'Etiketler'
    post:
        one: 'Gönderi'
        other: 'Gönderiler'
    page:
        one: 'Sayfa'
        other: 'Sayfalar'
    prev: 'Önceki'
    next: 'Sonraki'
widget:
    follow: 'TAKİP ET'
    recents: 'Son'
    links: 'Linkler'
    catalogue: 'Katalog'
    subscribe_email: 'Güncellemeler için abone olun'
    subscribe: 'Abone ol'
    adsense: 'İlan'
    followit: 'follow.it'
article:
    created_at: '%s&nbsp;yayınlandı'
    updated_at: '%s&nbsp;güncellendi'
    more: 'Daha fazla oku'
    comments: 'Yorumlar'
    read_time: '%s okuma süresi'
    word_count:
        one: 'Yaklaşık %d kelime'
        other: 'Yaklaşık %d kelime'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Bu makaleyi beğendiniz mi? Yazarı şununla destekleyin'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Bana bir kahve al'
plugin:
    backtotop: 'Başa dönüş'
    visit_count: '%s&nbsp;ziyaret'
    visitor_count: '%s kullanıcı tarafından ziyaret edildi'
    cookie_consent:
      message: Bu web sitesi, deneyiminizi geliştirmek için çerezler kullanır.
      dismiss: Anladım!
      allow: Çerezlere izin ver
      deny: Reddet
      link: Daha fazla bilgi edin
      policy: Çerez politikası
search:
    search: 'Ara'
    hint: 'Bir şeyler yaz...'
    no_result: 'İçin sonuç yok'
    untitled: '(Başlıksız)'
    empty_preview: '(Önizleme yok)'


================================================
FILE: languages/vn.yml
================================================
common:
    archive:
        one: 'Lưu trữ'
        other: 'Lưu trữ'
    category:
        one: 'Thể loại'
        other: 'Thể loại'
    tag:
        one: 'Nhãn'
        other: 'Nhãn'
    post:
        one: 'Bài viết'
        other: 'Bài viết'
    page:
        one: 'Trang'
        other: 'Trang'
    prev: 'Trước'
    next: 'Sau'
widget:
    follow: 'Theo dõi'
    recents: 'Gần đây'
    links: 'Link'
    catalogue: 'Mục lục'
    subscribe_email: 'Theo dõi các bản cập nhật'
    subscribe: 'Theo dõi'
    adsense: 'Quảng cáo'
    followit: 'follow.it'
article:
    created_at: 'Đã đăng&nbsp;%s'
    updated_at: 'Đã cập nhật&nbsp;%s'
    more: 'Đọc thêm'
    comments: 'Bình luận'
    read_time: '%s đọc'
    word_count:
        one: 'Khoảng %d từ'
        other: 'Khoảng %d từ'
    licensing:
        author: 'Author'
        created_at: 'Posted on'
        updated_at: 'Updated on'
        licensed_under: 'Licensed under'
donate:
    title: 'Bạn đọc có thể ủng hộ blog qua'
    afdian: 'Afdian.net'
    alipay: 'Alipay'
    wechat: 'Wechat'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: 'Mua cho tôi một ly cà phê'
plugin:
    backtotop: 'Trở lai đầu trang'
    visit_count: '%s&nbsp;Bạn đọc'
    visitor_count: 'Thăm bởi %s bạn đọc'
    cookie_consent:
      message: Trang web này sử dụng cookie để cải thiện trải nghiệm của bạn.
      dismiss: Hiểu rồi!
      allow: Cho phép cookie
      deny: Từ chối
      link: Tìm hiểu thêm
      policy: Chính sách Cookie
search:
    search: 'Tìm kiếm'
    hint: 'Gõ gì đó...'
    no_result: 'Không có kết quả cho'
    untitled: '(Không có tiêu đề)'
    empty_preview: '(Không có xem trước)'


================================================
FILE: languages/zh-CN.yml
================================================
common:
    archive:
        one: '归档'
        other: '归档'
    category:
        one: '分类'
        other: '分类'
    tag:
        one: '标签'
        other: '标签'
    post:
        one: '文章'
        other: '文章'
    page:
        one: '页面'
        other: '页面'
    prev: '上一页'
    next: '下一页'
widget:
    follow: '关注我'
    recents: '最新文章'
    links: '链接'
    catalogue: '目录'
    subscribe_email: '订阅更新'
    subscribe: '订阅'
    adsense: '广告'
    followit: 'follow.it'
article:
    created_at: '%s发表'
    updated_at: '%s更新'
    more: '阅读更多'
    comments: '评论'
    read_time: '%s读完'
    word_count:
        one: '大约%d个字'
        other: '大约%d个字'
    licensing:
        author: '作者'
        created_at: '发布于'
        updated_at: '更新于'
        licensed_under: '许可协议'
donate:
    title: '喜欢这篇文章?打赏一下作者吧'
    afdian: '爱发电'
    alipay: '支付宝'
    wechat: '微信'
    paypal: 'Paypal'
    patreon: 'Patreon'
    buymeacoffee: '送我杯咖啡'
plugin:
    backtotop: '回到顶端'
    visit_count: '%s次访问'
    visitor_count: '共%s个访客'
    cookie_consent:
      message: 此网站使用Cookie来改善您的体验。
      dismiss: 知道了!
      allow: 允许使用Cookie
      deny: 拒绝
      link: 了解更多
      policy: Cookie政策
search:
    search: '搜索'
    hint: '想要查找什么...'
    no_result: '未找到搜索结果'
    untitled: '(无标题)'
    empty_preview: '(无内容预览)'


================================================
FILE: languages/zh-TW.yml
================================================
common:
    archive:
        one: '彙整'
        other: '彙整'
    category:
        one: '分類'
        other: '分類'
    tag:
        one: '標籤'
        other: '標籤'
    post:
        one: '文章'
        other: '文章'
    page:
        one: '頁面'
        other: '頁面'
    prev: '上一頁'
    next: '下一頁'
widget:
    follow: '追蹤'
    recents: '最新文章'
    links: '連結'
    catalogue: '文章目錄'
    subscribe_email: '訂閱 Email'
    subscribe: '訂閱'
    adsense: '廣告'
    followit: 'follow.it'
article:
    created_at: '%s發表'
    updated_at: '%s更新'
    more: '繼續閱讀'
    comments: '評論'
    read_time: '%s讀完'
    word_count:
        one: '大約%d個字'
        other: '大約%d個字'
    licensing:
        author: '作者'
        created_at: '發表於'
        updated_at: '更新於'
        licensed_under: '許可協議'
donate:
    title: '喜歡這篇文章嗎? 贊助一下作者吧!'
    afdian: '愛發電'
    alipay: '支付寶'
    wechat: 'WeChat'
    paypal: 'PayPal'
    patreon: 'Patreon'
    buymeacoffee: '送我杯咖啡'
plugin:
    backtotop: '回到頁首'
    visit_count: '%s次訪問'
    visitor_count: '共%s個訪客'
    cookie_consent:
      message: 此網站使用Cookie來改善您的體驗。
      dismiss: 知道了!
      allow: 允許使用Cookie
      deny: 拒絕
      link: 了解更多
      policy: Cookie政策
search:
    search: '搜尋'
    hint: '請輸入關鍵字...'
    no_result: '未找到搜索結果'
    untitled: '(無標題)'
    empty_preview: '(無內容預覽)'


================================================
FILE: layout/archive.jsx
================================================
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
const ArticleMedia = require('hexo-component-inferno/lib/view/common/article_media');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { url_for, __, date_xml, date } = helper;

        const language = toMomentLocale(page.lang || page.language || config.language);

        function renderArticleList(posts, year, month = null) {
            const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));

            return <div class="card">
                <div class="card-content">
                    <h3 class="tag is-primary">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
                    <div class="timeline">
                        {posts.map(post => {
                            const categories = post.categories.map(category => ({
                                url: url_for(category.path),
                                name: category.name
                            }));
                            return <ArticleMedia
                                url={url_for(post.link || post.path)}
                                title={post.title}
                                date={date(post.date)}
                                dateXml={date_xml(post.date)}
                                categories={categories}
                                thumbnail={post.thumbnail ? url_for(post.thumbnail) : null} />;
                        })}
                    </div>
                </div>
            </div>;
        }

        let articleList;
        if (!page.year) {
            const years = {};
            page.posts.each(p => { years[p.date.year()] = null; });
            articleList = Object.keys(years).sort((a, b) => b - a).map(year => {
                const posts = page.posts.filter(p => p.date.year() === parseInt(year, 10));
                return renderArticleList(posts, year, null);
            });
        } else {
            articleList = renderArticleList(page.posts, page.year, page.month);
        }

        return <Fragment>
            {articleList}
            {page.total > 1 ? <Paginator
                current={page.current}
                total={page.total}
                baseUrl={page.base}
                path={config.pagination_dir}
                urlFor={url_for}
                prevTitle={__('common.prev')}
                nextTitle={__('common.next')} /> : null}
        </Fragment>;
    }
};


================================================
FILE: layout/categories.jsx
================================================
const { Component } = require('inferno');
const Categories = require('hexo-component-inferno/lib/view/widget/categories');

module.exports = class extends Component {
    render() {
        const { site, page, helper } = this.props;

        return <Categories.Cacheable site={site} page={page} helper={helper} />;
    }
};


================================================
FILE: layout/category.jsx
================================================
const { Component, Fragment } = require('inferno');
const Index = require('./index');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { url_for, _p } = helper;

        return <Fragment>
            <div class="card">
                <div class="card-content">
                    <nav class="breadcrumb" aria-label="breadcrumbs">
                        <ul>
                            <li><a href={url_for('/categories/')}>{_p('common.category', Infinity)}</a></li>
                            {page.parents.map(category => {
                                return <li><a href={url_for(category.path)}>{category.name}</a></li>;
                            })}
                            <li class="is-active"><a href="#" aria-current="page">{page.category}</a></li>
                        </ul>
                    </nav>
                </div>
            </div>
            <Index config={config} page={page} helper={helper} />
        </Fragment>;
    }
};


================================================
FILE: layout/comment/.gitkeep
================================================


================================================
FILE: layout/common/article.jsx
================================================
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Share = require('./share');
const Donates = require('./donates');
const Comment = require('./comment');
const ArticleLicensing = require('hexo-component-inferno/lib/view/misc/article_licensing');

/**
 * Get the word count of text.
 */
function getWordCount(content) {
    if (typeof content === 'undefined') {
        return 0;
    }
    content = content.replace(/<\/?[a-z][^>]*>/gi, '');
    content = content.trim();
    return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
}

module.exports = class extends Component {
    render() {
        const { config, helper, page, index } = this.props;
        const { article, plugins } = config;
        const { url_for, date, date_xml, __, _p } = helper;

        const defaultLanguage = Array.isArray(config.language) && config.language.length ? config.language[0] : config.language;

        const indexLanguage = toMomentLocale(defaultLanguage || 'en');
        const language = toMomentLocale(page.lang || page.language || defaultLanguage || 'en');
        const cover = page.cover ? url_for(page.cover) : null;
        const updateTime = article && article.update_time !== undefined ? article.update_time : true;
        const isUpdated = page.updated && !moment(page.date).isSame(moment(page.updated));
        const shouldShowUpdated = page.updated && ((updateTime === 'auto' && isUpdated) || updateTime === true);

        return <Fragment>
            {/* Main content */}
            <div class="card">
                {/* Thumbnail */}
                {cover ? <div class="card-image">
                    {index ? <a href={url_for(page.link || page.path)} class="image is-7by3">
                        <img class="fill" src={cover} alt={page.title || cover} />
                    </a> : <span class="image is-7by3">
                        <img class="fill" src={cover} alt={page.title || cover} />
                    </span>}
                </div> : null}
                <article class={`card-content article${'direction' in page ? ' ' + page.direction : ''}`} role="article">
                    {/* Metadata */}
                    {page.layout !== 'page' ? <div class="article-meta is-size-7 is-uppercase level is-mobile">
                        <div class="level-left">
                            {/* PIN Icon */}
                            {page.top ? <i class="fas fa-thumbtack level-item" title="Pinned"></i> : null}
                            {/* Creation Date */}
                            {page.date && <span class="level-item" dangerouslySetInnerHTML={{
                                __html: _p('article.created_at', `<time dateTime="${date_xml(page.date)}" title="${new Date(page.date).toLocaleString()}">${date(page.date)}</time>`)
                            }}></span>}
                            {/* Last Update Date */}
                            {shouldShowUpdated && <span class="level-item" dangerouslySetInnerHTML={{
                                __html: _p('article.updated_at', `<time dateTime="${date_xml(page.updated)}" title="${new Date(page.updated).toLocaleString()}">${date(page.updated)}</time>`)
                            }}></span>}
                            {/* author */}
                            {page.author ? <span class="level-item"> {page.author} </span> : null}
                            {/* Categories */}
                            {page.categories && page.categories.length ? <span class="level-item">
                                {(() => {
                                    const categories = [];
                                    page.categories.forEach((category, i) => {
                                        categories.push(<a class="link-muted" href={url_for(category.path)}>{category.name}</a>);
                                        if (i < page.categories.length - 1) {
                                            categories.push(<span>&nbsp;/&nbsp;</span>);
                                        }
                                    });
                                    return categories;
                                })()}
                            </span> : null}
                            {/* Read time */}
                            {article && article.readtime && article.readtime === true ? <span class="level-item">
                                {(() => {
                                    const words = getWordCount(page._content);
                                    const time = moment.duration((words / 150.0) * 60, 'seconds');
                                    return `${_p('article.read_time', time.locale(index ? indexLanguage : language).humanize())} (${_p('article.word_count', words)})`;
                                })()}
                            </span> : null}
                            {/* Visitor counter */}
                            {!index && plugins && plugins.busuanzi === true ? <span class="level-item" id="busuanzi_container_page_pv" dangerouslySetInnerHTML={{
                                __html: _p('plugin.visit_count', '<span id="busuanzi_value_page_pv">0</span>')
                            }}></span> : null}
                        </div>
                    </div> : null}
                    {/* Title */}
                    {page.title !== '' && index ? <p class="title is-3 is-size-4-mobile"><a class="link-muted" href={url_for(page.link || page.path)}>{page.title}</a></p> : null}
                    {page.title !== '' && !index ? <h1 class="title is-3 is-size-4-mobile">{page.title}</h1> : null}
                    {/* Content/Excerpt */}
                    <div class="content" dangerouslySetInnerHTML={{ __html: index && page.excerpt ? page.excerpt : page.content }}></div>
                    {/* Licensing block */}
                    {!index && article && article.licenses && Object.keys(article.licenses)
                        ? <ArticleLicensing.Cacheable page={page} config={config} helper={helper} /> : null}
                    {/* Tags */}
                    {!index && page.tags && page.tags.length ? <div class="article-tags is-size-7 mb-4">
                        <span class="mr-2">#</span>
                        {page.tags.map(tag => {
                            return <a class="link-muted mr-2" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
                        })}
                    </div> : null}
                    {/* "Read more" button */}
                    {index && page.excerpt ? <a class="article-more button is-small is-size-7" href={`${url_for(page.link || page.path)}#more`}>{__('article.more')}</a> : null}
                    {/* Share button */}
                    {!index ? <Share config={config} page={page} helper={helper} /> : null}
                </article>
            </div>
            {/* Donate button */}
            {!index ? <Donates config={config} helper={helper} /> : null}
            {/* Post navigation */}
            {!index && (page.prev || page.next) ? <nav class="post-navigation mt-4 level is-mobile">
                {page.prev ? <div class="level-start">
                    <a class={`article-nav-prev level level-item${!page.prev ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.prev.path)}>
                        <i class="level-item fas fa-chevron-left"></i>
                        <span class="level-item">{page.prev.title}</span>
                    </a>
                </div> : null}
                {page.next ? <div class="level-end">
                    <a class={`article-nav-next level level-item${!page.next ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.next.path)}>
                        <span class="level-item">{page.next.title}</span>
                        <i class="level-item fas fa-chevron-right"></i>
                    </a>
                </div> : null}
            </nav> : null}
            {/* Comment */}
            {!index ? <Comment config={config} page={page} helper={helper} /> : null}
        </Fragment>;
    }
};


================================================
FILE: layout/common/comment.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');

const logger = createLogger.default();

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { __ } = helper;
        const { comment } = config;
        if (!comment || typeof comment.type !== 'string') {
            return null;
        }

        return <div class="card" id="comments">
            <div class="card-content">
                <h3 class="title is-5">{__('article.comments')}</h3>
                {(() => {
                    try {
                        let Comment = view.require('comment/' + comment.type);
                        Comment = Comment.Cacheable ? Comment.Cacheable : Comment;
                        return <Comment config={config} page={page} helper={helper} comment={comment} />;
                    } catch (e) {
                        logger.w(`Icarus cannot load comment "${comment.type}"`);
                        return null;
                    }
                })()}
            </div>
        </div>;
    }
};


================================================
FILE: layout/common/donates.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');

const logger = createLogger.default();

module.exports = class extends Component {
    render() {
        const { config, helper } = this.props;
        const { __ } = helper;
        const { donates = [] } = config;
        if (!Array.isArray(donates) || !donates.length) {
            return null;
        }
        return <div class="card">
            <div class="card-content">
                <h3 class="menu-label has-text-centered">{__('donate.title')}</h3>
                <div class="buttons is-centered">
                    {donates.map(service => {
                        const type = service.type;
                        if (typeof type === 'string') {
                            try {
                                let Donate = view.require('donate/' + type);
                                Donate = Donate.Cacheable ? Donate.Cacheable : Donate;
                                return <Donate helper={helper} donate={service} />;
                            } catch (e) {
                                logger.w(`Icarus cannot load donate button "${type}"`);
                            }
                        }
                        return null;
                    })}
                </div>
            </div>
        </div>;
    }
};


================================================
FILE: layout/common/footer.jsx
================================================
const { Component } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');

class Footer extends Component {
    render() {
        const {
            logo,
            logoUrl,
            siteUrl,
            siteTitle,
            siteYear,
            author,
            links,
            copyright,
            showVisitorCounter,
            visitorCounterTitle
        } = this.props;

        let footerLogo = '';
        if (logo) {
            if (logo.text) {
                footerLogo = logo.text;
            } else {
                footerLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
            }
        } else {
            footerLogo = siteTitle;
        }

        return <footer class="footer">
            <div class="container">
                <div class="level">
                    <div class="level-start">
                        <a class="footer-logo is-block mb-2" href={siteUrl}>
                            {footerLogo}
                        </a>
                        <p class="is-size-7">
                            <span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
                            &nbsp;&nbsp;Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>&nbsp;&&nbsp;
                            <a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
                            {showVisitorCounter ? <br /> : null}
                            {showVisitorCounter ? <span id="busuanzi_container_site_uv"
                                dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
                        </p>
                        {copyright ? <p class="is-size-7" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
                    </div>
                    <div class="level-end">
                        {Object.keys(links).length ? <div class="field has-addons">
                            {Object.keys(links).map(name => {
                                const link = links[name];
                                return <p class="control">
                                    <a class={`button is-transparent ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
                                        {link.icon ? <i class={link.icon}></i> : name}
                                    </a>
                                </p>;
                            })}
                        </div> : null}
                    </div>
                </div>
            </div>
        </footer>;
    }
}

module.exports = cacheComponent(Footer, 'common.footer', props => {
    const { config, helper } = props;
    const { url_for, _p, date } = helper;
    const { logo, title, author, footer, plugins } = config;

    const links = {};
    if (footer && footer.links) {
        Object.keys(footer.links).forEach(name => {
            const link = footer.links[name];
            links[name] = {
                url: url_for(typeof link === 'string' ? link : link.url),
                icon: link.icon
            };
        });
    }

    return {
        logo,
        logoUrl: url_for(logo),
        siteUrl: url_for('/'),
        siteTitle: title,
        siteYear: date(new Date(), 'YYYY'),
        author,
        links,
        copyright: footer?.copyright ?? '',
        showVisitorCounter: plugins && plugins.busuanzi === true,
        visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>')
    };
});


================================================
FILE: layout/common/head.jsx
================================================
const { Component } = require('inferno');
const MetaTags = require('hexo-component-inferno/lib/view/misc/meta');
const WebApp = require('hexo-component-inferno/lib/view/misc/web_app');
const OpenGraph = require('hexo-component-inferno/lib/view/misc/open_graph');
const StructuredData = require('hexo-component-inferno/lib/view/misc/structured_data');
const Plugins = require('./plugins');

function getPageTitle(page, siteTitle, helper) {
    let title = page.title;

    if (helper.is_archive()) {
        title = helper._p('common.archive', Infinity);
        if (helper.is_month()) {
            title += ': ' + page.year + '/' + page.month;
        } else if (helper.is_year()) {
            title += ': ' + page.year;
        }
    } else if (helper.is_category()) {
        title = helper._p('common.category', 1) + ': ' + page.category;
    } else if (helper.is_tag()) {
        title = helper._p('common.tag', 1) + ': ' + page.tag;
    } else if (helper.is_categories()) {
        title = helper._p('common.category', Infinity);
    } else if (helper.is_tags()) {
        title = helper._p('common.tag', Infinity);
    }

    return [title, siteTitle].filter(str => typeof str !== 'undefined' && str.trim() !== '').join(' - ');
}

module.exports = class extends Component {
    render() {
        const { site, config, helper, page } = this.props;
        const { url_for, cdn, fontcdn, iconcdn, is_post } = helper;
        const {
            url,
            head = {},
            article,
            highlight,
            variant = 'default'
        } = config;
        const {
            meta = [],
            manifest = {},
            open_graph = {},
            structured_data = {},
            canonical_url = page.permalink,
            rss,
            favicon
        } = head;

        const noIndex = helper.is_archive() || helper.is_category() || helper.is_tag();

        const language = page.lang || page.language || config.language;
        const fontCssUrl = {
            default: fontcdn('Ubuntu:wght@400;600&family=Source+Code+Pro', 'css2'),
            cyberpunk: fontcdn('Oxanium:wght@300;400;600&family=Roboto+Mono', 'css2')
        };

        let hlTheme, images;
        if (highlight && highlight.enable === false) {
            hlTheme = null;
        } else if (article && article.highlight && article.highlight.theme) {
            hlTheme = article.highlight.theme;
        } else {
            hlTheme = 'atom-one-light';
        }

        if (typeof page.og_image === 'string') {
            images = [page.og_image];
        } else if (typeof page.cover === 'string') {
            images = [url_for(page.cover)];
        } else if (typeof page.thumbnail === 'string') {
            images = [url_for(page.thumbnail)];
        } else if (article && typeof article.og_image === 'string') {
            images = [article.og_image];
        } else if (page.content && page.content.includes('<img')) {
            let img;
            images = [];
            const imgPattern = /<img [^>]*src=['"]([^'"]+)([^>]*>)/gi;
            while ((img = imgPattern.exec(page.content)) !== null) {
                images.push(img[1]);
            }
        } else {
            images = [url_for('/img/og_image.png')];
        }

        let adsenseClientId = null;
        if (Array.isArray(config.widgets)) {
            const widget = config.widgets.find(widget => widget.type === 'adsense');
            if (widget) {
                adsenseClientId = widget.client_id;
            }
        }

        let openGraphImages = images;
        if ((typeof open_graph === 'object' && open_graph !== null)
            && ((Array.isArray(open_graph.image) && open_graph.image.length > 0) || typeof open_graph.image === 'string')) {
            openGraphImages = open_graph.image;
        } else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
            openGraphImages = page.photos;
        }

        let structuredImages = images;
        if ((typeof structured_data === 'object' && structured_data !== null)
            && ((Array.isArray(structured_data.image) && structured_data.image.length > 0) || typeof structured_data.image === 'string')) {
            structuredImages = structured_data.image;
        } else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
            structuredImages = page.photos;
        }

        let followItVerificationCode = null;
        if (Array.isArray(config.widgets)) {
            const widget = config.widgets.find(widget => widget.type === 'followit');
            if (widget) {
                followItVerificationCode = widget.verification_code;
            }
        }

        return <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
            {noIndex ? <meta name="robots" content="noindex" /> : null}
            {meta && meta.length ? <MetaTags meta={meta} /> : null}

            <title>{getPageTitle(page, config.title, helper)}</title>

            <WebApp.Cacheable
                helper={helper}
                favicon={favicon}
                icons={manifest.icons}
                themeColor={manifest.theme_color}
                name={manifest.name || config.title} />

            {typeof open_graph === 'object' && open_graph !== null ? <OpenGraph
                type={open_graph.type || (is_post(page) ? 'article' : 'website')}
                title={open_graph.title || page.title || config.title}
                date={page.date}
                updated={page.updated}
                author={open_graph.author || config.author}
                description={open_graph.description || page.description || page.excerpt || page.content || config.description}
                keywords={(page.tags && page.tags.length ? page.tags : undefined) || config.keywords}
                url={open_graph.url || page.permalink || url}
                images={openGraphImages}
                siteName={open_graph.site_name || config.title}
                language={language}
                twitterId={open_graph.twitter_id}
                twitterCard={open_graph.twitter_card}
                twitterSite={open_graph.twitter_site}
                googlePlus={open_graph.google_plus}
                facebookAdmins={open_graph.fb_admins}
                facebookAppId={open_graph.fb_app_id} /> : null}

            {typeof structured_data === 'object' && structured_data !== null ? <StructuredData
                title={structured_data.title || page.title || config.title}
                description={structured_data.description || page.description || page.excerpt || page.content || config.description}
                url={structured_data.url || page.permalink || url}
                author={structured_data.author || config.author}
                publisher={structured_data.publisher || config.title}
                publisherLogo={structured_data.publisher_logo || config.logo}
                date={page.date}
                updated={page.updated}
                images={structuredImages} /> : null}

            {canonical_url ? <link rel="canonical" href={canonical_url} /> : null}
            {rss ? <link rel="alternate" href={url_for(rss)} title={config.title} type="application/atom+xml" /> : null}
            {favicon ? <link rel="icon" href={url_for(favicon)} /> : null}
            <link rel="stylesheet" href={iconcdn()} />
            {hlTheme ? <link data-pjax rel="stylesheet" href={cdn('highlight.js', '11.7.0', 'styles/' + hlTheme + '.css')} /> : null}
            <link rel="stylesheet" href={fontCssUrl[variant]} />
            <link data-pjax rel="stylesheet" href={url_for('/css/' + variant + '.css')} />
            <Plugins site={site} config={config} helper={helper} page={page} head={true} />

            {adsenseClientId ? <script data-ad-client={adsenseClientId}
                src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async></script> : null}

            {followItVerificationCode ? <meta name="follow.it-verification-code" content={followItVerificationCode} /> : null}
        </head>;
    }
};


================================================
FILE: layout/common/navbar.jsx
================================================
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
const classname = require('hexo-component-inferno/lib/util/classname');

function isSameLink(a, b) {
    function santize(url) {
        let paths = url.replace(/(^\w+:|^)\/\//, '').split('#')[0].split('/').filter(p => p.trim() !== '');
        if (paths.length > 0 && paths[paths.length - 1].trim() === 'index.html') {
            paths = paths.slice(0, paths.length - 1);
        }
        return paths.join('/');
    }
    return santize(a) === santize(b);
}

class Navbar extends Component {
    render() {
        const {
            logo,
            logoUrl,
            siteUrl,
            siteTitle,
            menu,
            links,
            showToc,
            tocTitle,
            showSearch,
            searchTitle
        } = this.props;

        let navbarLogo = '';
        if (logo) {
            if (logo.text) {
                navbarLogo = logo.text;
            } else {
                navbarLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
            }
        } else {
            navbarLogo = siteTitle;
        }

        return <nav class="navbar navbar-main">
            <div class="container navbar-container">
                <div class="navbar-brand justify-content-center">
                    <a class="navbar-item navbar-logo" href={siteUrl}>
                        {navbarLogo}
                    </a>
                </div>
                <div class="navbar-menu">
                    {Object.keys(menu).length ? <div class="navbar-start">
                        {Object.keys(menu).map(name => {
                            const item = menu[name];
                            return <a class={classname({ 'navbar-item': true, 'is-active': item.active })} href={item.url}>{name}</a>;
                        })}
                    </div> : null}
                    <div class="navbar-end">
                        {Object.keys(links).length ? <Fragment>
                            {Object.keys(links).map(name => {
                                const link = links[name];
                                return <a class="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
                                    {link.icon ? <i class={link.icon}></i> : name}
                                </a>;
                            })}
                        </Fragment> : null}
                        {showToc ? <a class="navbar-item is-hidden-tablet catalogue" title={tocTitle} href="javascript:;">
                            <i class="fas fa-list-ul"></i>
                        </a> : null}
                        {showSearch ? <a class="navbar-item search" title={searchTitle} href="javascript:;">
                            <i class="fas fa-search"></i>
                        </a> : null}
                    </div>
                </div>
            </div>
        </nav>;
    }
}

module.exports = cacheComponent(Navbar, 'common.navbar', props => {
    const { config, helper, page } = props;
    const { url_for, _p, __ } = helper;
    const { logo, title, navbar, widgets, search } = config;

    const hasTocWidget = Array.isArray(widgets) && widgets.find(widget => widget.type === 'toc');
    const showToc = (config.toc === true || page.toc) && hasTocWidget && ['page', 'post'].includes(page.layout);

    const menu = {};
    if (navbar && navbar.menu) {
        const pageUrl = typeof page.path !== 'undefined' ? url_for(page.path) : '';
        Object.keys(navbar.menu).forEach(name => {
            const url = url_for(navbar.menu[name]);
            const active = isSameLink(url, pageUrl);
            menu[name] = { url, active };
        });
    }

    const links = {};
    if (navbar && navbar.links) {
        Object.keys(navbar.links).forEach(name => {
            const link = navbar.links[name];
            links[name] = {
                url: url_for(typeof link === 'string' ? link : link.url),
                icon: link.icon
            };
        });
    }

    return {
        logo,
        logoUrl: url_for(logo),
        siteUrl: url_for('/'),
        siteTitle: title,
        menu,
        links,
        showToc,
        tocTitle: _p('widget.catalogue', Infinity),
        showSearch: search && search.type,
        searchTitle: __('search.search')
    };
});


================================================
FILE: layout/common/plugins.jsx
================================================
const createLogger = require('hexo-log');
const { Component, Fragment } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');

const logger = createLogger.default();

module.exports = class extends Component {
    render() {
        const { site, config, page, helper, head } = this.props;
        const { plugins = [] } = config;

        return <Fragment>
            {Object.keys(plugins).map(name => {
                // plugin is not enabled
                if (!plugins[name]) {
                    return null;
                }
                try {
                    let Plugin = view.require('plugin/' + name);
                    Plugin = Plugin.Cacheable ? Plugin.Cacheable : Plugin;
                    return <Plugin site={site} config={config} page={page} helper={helper} plugin={plugins[name]} head={head} />;
                } catch (e) {
                    logger.w(`Icarus cannot load plugin "${name}"`);
                    return null;
                }
            })}
        </Fragment>;
    }
};


================================================
FILE: layout/common/scripts.jsx
================================================
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Plugins = require('./plugins');

module.exports = class extends Component {
    render() {
        const { site, config, helper, page } = this.props;
        const { url_for, cdn } = helper;
        const { article } = config;
        const language = toMomentLocale(page.lang || page.language || config.language || 'en');

        let fold = 'unfolded';
        let clipboard = true;
        if (article && article.highlight) {
            if (typeof article.highlight.clipboard !== 'undefined') {
                clipboard = !!article.highlight.clipboard;
            }
            if (typeof article.highlight.fold === 'string') {
                fold = article.highlight.fold;
            }
        }

        const embeddedConfig = `var IcarusThemeSettings = {
            article: {
                highlight: {
                    clipboard: ${clipboard},
                    fold: '${fold}'
                }
            }
        };`;

        return <Fragment>
            <script src={cdn('jquery', '3.3.1', 'dist/jquery.min.js')}></script>
            <script src={cdn('moment', '2.22.2', 'min/moment-with-locales.min.js')}></script>
            {clipboard && <script src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')} defer></script>}
            <script dangerouslySetInnerHTML={{ __html: `moment.locale("${language}");` }}></script>
            <script dangerouslySetInnerHTML={{ __html: embeddedConfig }}></script>
            <script data-pjax src={url_for('/js/column.js')}></script>
            <Plugins site={site} config={config} page={page} helper={helper} head={false} />
            <script data-pjax src={url_for('/js/main.js')} defer></script>
        </Fragment>;
    }
};


================================================
FILE: layout/common/search.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');

const logger = createLogger.default();

module.exports = class extends Component {
    render() {
        const { config, helper } = this.props;
        const { search } = config;
        if (!search || typeof search.type !== 'string') {
            return null;
        }

        try {
            let Search = view.require('search/' + search.type);
            Search = Search.Cacheable ? Search.Cacheable : Search;
            return <Search config={config} helper={helper} search={search} />;
        } catch (e) {
            logger.w(`Icarus cannot load search "${search.type}"`);
            return null;
        }
    }
};


================================================
FILE: layout/common/share.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');

const logger = createLogger.default();

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { share } = config;
        if (!share || typeof share.type !== 'string') {
            return null;
        }

        try {
            let Share = view.require('share/' + share.type);
            Share = Share.Cacheable ? Share.Cacheable : Share;
            return <Share config={config} page={page} helper={helper} share={share} />;
        } catch (e) {
            logger.w(`Icarus cannot load share button "${share.type}"`);
            return null;
        }
    }
};


================================================
FILE: layout/common/widgets.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const classname = require('hexo-component-inferno/lib/util/classname');

const logger = createLogger.default();

function formatWidgets(widgets) {
    const result = {};
    if (Array.isArray(widgets)) {
        widgets.filter(widget => typeof widget === 'object').forEach(widget => {
            if ('position' in widget && (widget.position === 'left' || widget.position === 'right')) {
                if (!(widget.position in result)) {
                    result[widget.position] = [widget];
                } else {
                    result[widget.position].push(widget);
                }
            }
        });
    }
    return result;
}

function hasColumn(widgets, position, config, page) {
    const showToc = (config.toc === true) && ['page', 'post'].includes(page.layout);
    if (Array.isArray(widgets)) {
        return typeof widgets.find(widget => {
            if (widget.type === 'toc' && !showToc) {
                return false;
            }
            return widget.position === position;
        }) !== 'undefined';
    }
    return false;
}

function getColumnCount(widgets, config, page) {
    return [hasColumn(widgets, 'left', config, page), hasColumn(widgets, 'right', config, page)].filter(v => !!v).length + 1;
}

function getColumnSizeClass(columnCount) {
    switch (columnCount) {
        case 2:
            return 'is-4-tablet is-4-desktop is-4-widescreen';
        case 3:
            return 'is-4-tablet is-4-desktop is-3-widescreen';
    }
    return '';
}

function getColumnVisibilityClass(columnCount, position) {
    if (columnCount === 3 && position === 'right') {
        return 'is-hidden-touch is-hidden-desktop-only';
    }
    return '';
}

function getColumnOrderClass(position) {
    return position === 'left' ? 'order-1' : 'order-3';
}

function isColumnSticky(config, position) {
    return typeof config.sidebar === 'object'
        && position in config.sidebar
        && config.sidebar[position].sticky === true;
}

class Widgets extends Component {
    render() {
        const { site, config, helper, page, position } = this.props;
        const widgets = formatWidgets(config.widgets)[position] || [];
        const columnCount = getColumnCount(config.widgets, config, page);

        if (!widgets.length) {
            return null;
        }

        return <div class={classname({
            'column': true,
            ['column-' + position]: true,
            [getColumnSizeClass(columnCount)]: true,
            [getColumnVisibilityClass(columnCount, position)]: true,
            [getColumnOrderClass(position)]: true,
            'is-sticky': isColumnSticky(config, position)
        })}>
            {widgets.map(widget => {
                // widget type is not defined
                if (!widget.type) {
                    return null;
                }
                try {
                    let Widget = view.require('widget/' + widget.type);
                    Widget = Widget.Cacheable ? Widget.Cacheable : Widget;
                    return <Widget site={site} helper={helper} config={config} page={page} widget={widget} />;
                } catch (e) {
                    logger.w(`Icarus cannot load widget "${widget.type}"`);
                }
                return null;
            })}
            {position === 'left' && hasColumn(config.widgets, 'right', config, page) ? <div class={classname({
                'column-right-shadow': true,
                'is-hidden-widescreen': true,
                'is-sticky': isColumnSticky(config, 'right')
            })}></div> : null}
        </div>;
    }
}

Widgets.getColumnCount = getColumnCount;

module.exports = Widgets;


================================================
FILE: layout/donate/.gitkeep
================================================


================================================
FILE: layout/index.jsx
================================================
const { Component, Fragment } = require('inferno');
const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
const Article = require('./common/article');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { __, url_for } = helper;

        return <Fragment>
            {page.posts.map(post => <Article config={config} page={post} helper={helper} index={true} />)}
            {page.total > 1 ? <Paginator
                current={page.current}
                total={page.total}
                baseUrl={page.base}
                path={config.pagination_dir}
                urlFor={url_for}
                prevTitle={__('common.prev')}
                nextTitle={__('common.next')} /> : null}
        </Fragment>;
    }
};


================================================
FILE: layout/layout.jsx
================================================
const { Component } = require('inferno');
const classname = require('hexo-component-inferno/lib/util/classname');
const Head = require('./common/head');
const Navbar = require('./common/navbar');
const Widgets = require('./common/widgets');
const Footer = require('./common/footer');
const Scripts = require('./common/scripts');
const Search = require('./common/search');

module.exports = class extends Component {
    render() {
        const { site, config, page, helper, body } = this.props;

        const language = page.lang || page.language || config.language;
        const columnCount = Widgets.getColumnCount(config.widgets, config, page);

        return <html lang={language ? language.substr(0, 2) : ''}>
            <Head site={site} config={config} helper={helper} page={page} />
            <body class={`is-${columnCount}-column`}>
                <Navbar config={config} helper={helper} page={page} />
                <section class="section">
                    <div class="container">
                        <div class="columns">
                            <div class={classname({
                                column: true,
                                'order-2': true,
                                'column-main': true,
                                'is-12': columnCount === 1,
                                'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
                                'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3
                            })} dangerouslySetInnerHTML={{ __html: body }}></div>
                            <Widgets site={site} config={config} helper={helper} page={page} position={'left'} />
                            <Widgets site={site} config={config} helper={helper} page={page} position={'right'} />
                        </div>
                    </div>
                </section>
                <Footer config={config} helper={helper} />
                <Scripts site={site} config={config} helper={helper} page={page} />
                <Search config={config} helper={helper} />
            </body>
        </html>;
    }
};


================================================
FILE: layout/misc/.gitkeep
================================================


================================================
FILE: layout/page.jsx
================================================
const { Component } = require('inferno');
const Article = require('./common/article');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;

        return <Article config={config} page={page} helper={helper} index={false} />;
    }
};


================================================
FILE: layout/plugin/animejs.jsx
================================================
const { Component } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');

class AnimeJs extends Component {
    render() {
        if (this.props.head) {
            return <style dangerouslySetInnerHTML={{ __html: 'body>.footer,body>.navbar,body>.section{opacity:0}' }}></style>;
        }
        return <script src={this.props.jsUrl}></script>;

    }
}

AnimeJs.Cacheable = cacheComponent(AnimeJs, 'plugin.animejs', props => {
    const { helper, head } = props;
    return {
        head,
        jsUrl: helper.url_for('/js/animation.js')
    };
});

module.exports = AnimeJs;


================================================
FILE: layout/plugin/back_to_top.jsx
================================================
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');

class BackToTop extends Component {
    render() {
        const { title, jsUrl } = this.props;

        return <Fragment>
            <a id="back-to-top" title={title} href="javascript:;">
                <i class="fas fa-chevron-up"></i>
            </a>
            <script data-pjax src={jsUrl} defer></script>
        </Fragment>;

    }
}

BackToTop.Cacheable = cacheComponent(BackToTop, 'plugin.backtotop', props => {
    const { helper, head } = props;
    if (head) {
        return null;
    }
    return {
        title: helper.__('plugin.backtotop'),
        jsUrl: helper.url_for('/js/back_to_top.js')
    };
});

module.exports = BackToTop;


================================================
FILE: layout/plugin/pjax.jsx
================================================
const { Component, Fragment } = require('inferno');

class Pjax extends Component {
    render() {
        if (this.props.head) {
            return null;
        }
        const { helper } = this.props;
        const { url_for, cdn } = helper;

        return <Fragment>
            <script src={cdn('pjax', '0.2.8', 'pjax.min.js')}></script>
            <script src={url_for('/js/pjax.js')}></script>
        </Fragment>;
    }
}

module.exports = Pjax;


================================================
FILE: layout/post.jsx
================================================
const { Component } = require('inferno');
const Article = require('./common/article');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;

        return <Article config={config} page={page} helper={helper} index={false} />;
    }
};


================================================
FILE: layout/search/.gitkeep
================================================


================================================
FILE: layout/share/.gitkeep
================================================


================================================
FILE: layout/tag.jsx
================================================
const { Component, Fragment } = require('inferno');
const Index = require('./index');

module.exports = class extends Component {
    render() {
        const { config, page, helper } = this.props;
        const { url_for, _p } = helper;

        return <Fragment>
            <div class="card">
                <div class="card-content">
                    <nav class="breadcrumb" aria-label="breadcrumbs">
                        <ul>
                            <li><a href={url_for('/tags/')}>{_p('common.tag', Infinity)}</a></li>
                            <li class="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
                        </ul>
                    </nav>
                </div>
            </div>
            <Index config={config} page={page} helper={helper} />
        </Fragment>;
    }
};


================================================
FILE: layout/tags.jsx
================================================
const { Component } = require('inferno');
const Tags = require('hexo-component-inferno/lib/view/widget/tags');

module.exports = class extends Component {
    render() {
        const { site, helper } = this.props;

        return <Tags.Cacheable site={site} helper={helper} />;
    }
};


================================================
FILE: layout/widget/profile.jsx
================================================
const { Component } = require('inferno');
const gravatrHelper = require('hexo-util').gravatar;
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');

class Profile extends Component {
    renderSocialLinks(links) {
        if (!links.length) {
            return null;
        }
        return <div class="level is-mobile is-multiline">
            {links.filter(link => typeof link === 'object').map(link => {
                return <a class="level-item button is-transparent is-marginless"
                    target="_blank" rel="me noopener" title={link.name} href={link.url}>
                    {'icon' in link ? <i class={link.icon}></i> : link.name}
                </a>;
            })}
        </div>;
    }

    render() {
        const {
            avatar,
            avatarRounded,
            author,
            authorTitle,
            location,
            counter,
            followLink,
            followTitle,
            socialLinks
        } = this.props;
        return <div class="card widget" data-type="profile">
            <div class="card-content">
                <nav class="level">
                    <div class="level-item has-text-centered flex-shrink-1">
                        <div>
                            <figure class="image is-128x128 mx-auto mb-2">
                                <img class={'avatar' + (avatarRounded ? ' is-rounded' : '')} src={avatar} alt={author} />
                            </figure>
                            {author ? <p class="title is-size-4 is-block" style={{'line-height': 'inherit'}}>{author}</p> : null}
                            {authorTitle ? <p class="is-size-6 is-block">{authorTitle}</p> : null}
                            {location ? <p class="is-size-6 is-flex justify-content-center">
                                <i class="fas fa-map-marker-alt mr-1"></i>
                                <span>{location}</span>
                            </p> : null}
                        </div>
                    </div>
                </nav>
                <nav class="level is-mobile">
                    <div class="level-item has-text-centered is-marginless">
                        <div>
                            <p class="heading">{counter.post.title}</p>
                            <a href={counter.post.url}>
                                <p class="title">{counter.post.count}</p>
                            </a>
                        </div>
                    </div>
                    <div class="level-item has-text-centered is-marginless">
                        <div>
                            <p class="heading">{counter.category.title}</p>
                            <a href={counter.category.url}>
                                <p class="title">{counter.category.count}</p>
                            </a>
                        </div>
                    </div>
                    <div class="level-item has-text-centered is-marginless">
                        <div>
                            <p class="heading">{counter.tag.title}</p>
                            <a href={counter.tag.url}>
                                <p class="title">{counter.tag.count}</p>
                            </a>
                        </div>
                    </div>
                </nav>
                {followLink ? <div class="level">
                    <a class="level-item button is-primary is-rounded" href={followLink} target="_blank" rel="me noopener">{followTitle}</a>
                </div> : null}
                {socialLinks ? this.renderSocialLinks(socialLinks) : null}
            </div>
        </div>;
    }
}

Profile.Cacheable = cacheComponent(Profile, 'widget.profile', props => {
    const { site, helper, widget } = props;
    const {
        avatar,
        gravatar,
        avatar_rounded = false,
        author = props.config.author,
        author_title,
        location,
        follow_link,
        social_links
    } = widget;
    const { url_for, _p, __ } = helper;

    function getAvatar() {
        if (gravatar) {
            return gravatrHelper(gravatar, 128);
        }
        if (avatar) {
            return url_for(avatar);
        }
        return url_for('/img/avatar.png');
    }

    const postCount = site.posts.length;
    const categoryCount = site.categories.filter(category => category.length).length;
    const tagCount = site.tags.filter(tag => tag.length).length;

    const socialLinks = social_links ? Object.keys(social_links).map(name => {
        const link = social_links[name];
        if (typeof link === 'string') {
            return {
                name,
                url: url_for(link)
            };
        }
        return {
            name,
            url: url_for(link.url),
            icon: link.icon
        };
    }) : null;

    return {
        avatar: getAvatar(),
        avatarRounded: avatar_rounded,
        author,
        authorTitle: author_title,
        location,
        counter: {
            post: {
                count: postCount,
                title: _p('common.post', postCount),
                url: url_for('/archives/')
            },
            category: {
                count: categoryCount,
                title: _p('common.category', categoryCount),
                url: url_for('/categories/')
            },
            tag: {
                count: tagCount,
                title: _p('common.tag', tagCount),
                url: url_for('/tags/')
            }
        },
        followLink: follow_link ? url_for(follow_link) : undefined,
        followTitle: __('widget.follow'),
        socialLinks
    };
});

module.exports = Profile;


================================================
FILE: package.json
================================================
{
  "name": "hexo-theme-icarus",
  "version": "6.1.1",
  "author": "ppoffice <ppoffice@users.noreply.github.com>",
  "license": "MIT",
  "description": "A simple, delicate, and modern theme for Hexo",
  "keywords": [
    "hexo",
    "theme",
    "icarus"
  ],
  "homepage": "https://github.com/ppoffice/hexo-theme-icarus",
  "repository": "https://github.com/ppoffice/hexo-theme-icarus.git",
  "bugs": {
    "url": "https://github.com/ppoffice/hexo-theme-icarus/issues"
  },
  "engines": {
    "node": ">=14"
  },
  "scripts": {
    "lint": "eslint --ext .js --ext .jsx --ext .json ."
  },
  "devDependencies": {
    "eslint": "^8.56.0",
    "eslint-config-hexo": "^5.0.0",
    "eslint-plugin-json": "^3.1.0",
    "eslint-plugin-react": "^7.33.2"
  },
  "dependencies": {
    "bulma-stylus": "0.8.0",
    "deepmerge": "^4.3.1",
    "hexo": "^7.1.1",
    "hexo-component-inferno": "^3.1.2",
    "hexo-log": "^4.1.0",
    "hexo-pagination": "^3.0.0",
    "hexo-renderer-inferno": "^1.0.2",
    "hexo-renderer-stylus": "^3.0.1",
    "hexo-util": "^3.2.0",
    "inferno": "^8.2.3",
    "inferno-create-element": "^8.2.3",
    "moment": "^2.30.1",
    "semver": "^7.5.4"
  }
}


================================================
FILE: scripts/index.js
================================================
/* global hexo */
const createLogger = require('hexo-log');

const logger = createLogger.default();

/**
 * Print welcome message
 */
logger.info(`=======================================
 ██╗ ██████╗ █████╗ ██████╗ ██╗   ██╗███████╗
 ██║██╔════╝██╔══██╗██╔══██╗██║   ██║██╔════╝
 ██║██║     ███████║██████╔╝██║   ██║███████╗
 ██║██║     ██╔══██║██╔══██╗██║   ██║╚════██║
 ██║╚██████╗██║  ██║██║  ██║╚██████╔╝███████║
 ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝
=============================================`);

/**
 * Check if all dependencies are installed
 */
require('../include/dependency')(hexo);

/**
 * Configuration file checking and migration
 */
require('../include/config')(hexo);

/**
 * Register Hexo extensions and remove Hexo filters that could cause OOM
 */
require('../include/register')(hexo);


================================================
FILE: source/css/cyberpunk.styl
================================================
$family-sans-serif ?= 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif
$family-code ?= 'Roboto Mono', monospace, 'Microsoft YaHei'
// shadow and radius
$shadow ?= none
$radius ?= 0
$radius-small ?= 0
// base colors
$white ?= #fff
$white-bis ?= #cdcdcd
$grey ?= #848484
$black ?= #000
$black-bis ?= #050a0e
$orange ?= #ff8e3c
$yellow ?= #fcee09
$green ?= #00ff41
$blue ?= #02d7f2
$purple ?= #9561d2
$red ?= #ff003c
$primary ?= $yellow
$info ?= $blue
$success ?= $green
$warning ?= $orange
$danger ?= $red
// invert colors
$orange-invert ?= #121617
$yellow-invert ?= #121617
$green-invert ?= #121617
$blue-invert ?= #121617
$purple-invert ?= #121617
$red-invert ?= #121617
$primary-invert ?= #121617
$info-invert ?= #121617
$success-invert ?= #121617
$warning-invert ?= #121617
$danger-invert ?= #121617
// derived colors
$scheme-main ?= $black
$link ?= $blue
$link-hover ?= $primary
$text ?= $white-bis
$text-strong ?= $yellow
$body-background-color ?= $scheme-main
$input-color ?= $text
$input-placeholder-color ?= rgba($input-color, .8)
$footer-color ?= $black
$footer-background-color ?= $yellow
$navbar-background-color ?= $yellow
$navbar-item-color ?= $black
$navbar-item-active-color ?= $black
$navbar-item-hover-color ?= $black
$navbar-item-hover-background-color ?= transparent
$navbar-item-margin-v ?= 1.25rem
$navbar-item-margin-h ?= .25rem
$navbar-item-padding-v ?= 0
$navbar-item-padding-h ?= .5rem
$card-background-color ?= transparent
$menu-label-color ?= $blue
$menu-item-hover-color ?= $black
$menu-item-hover-background-color ?= $yellow
$menu-item-active-color ?= $black
$menu-item-active-background-color ?= $yellow
$menu-list-border-left ?= 1px solid $text
$tag-color ?= $black
$tag-background-color ?= $blue
$timeline-fg-line ?= $blue
$timeline-bg-line ?= $body-background-color
$post-navigation-fg ?= $white-bis
$searchbox-bg-container ?= $black-bis
$searchbox-border ?= $blue
$searchbox-bg-input ?= $black-bis
$searchbox-bg-close-hover ?= $black
$searchbox-bg-close-active ?= $searchbox-bg-close-hover
$searchbox-bg-result-item-hover ?= $black

@import 'style'

clip-path(clip)
    clip-path: clip
    -webkit-clip-path: clip

cut-corner(size)
    clip-path(unquote('polygon(' + size + ' 0, 100% 0, 100% calc(100% - ' + size + '), calc(100% - ' + size + ') 100%, 0 100%, 0 ' + size + ')'))

cut-corner-reverse(size)
    clip-path(unquote('polygon(0 0, calc(100% - ' + size + ') 0, 100% ' + size + ', 100% 100%, ' + size + ' 100%, 0 calc(100% - ' + size + '), 0 0)'))

cut-corner-top-right(size)
    clip-path(unquote('polygon(0 0, calc(100% - ' + size + ') 0, 100% ' + size + ', 100% 100%, 0 100%)'))

cut-corner-bottom-left(size)
    clip-path(unquote('polygon(0 0, 100% 0, 100% 100%, ' + size + ' 100%, 0 calc(100% - ' + size + '))'))

cut-corner-bottom-right(size)
    clip-path(unquote('polygon(0 0, 100% 0, 100% calc(100% - ' + size + '), calc(100% - ' + size + ') 100%, 0 100%)'))

undercover-before()
    position: relative

    &:before
        content: ''
        position: absolute
        z-index: -1
        top: 0
        left: 0
        right: 0
        bottom: 0

body
    counter-reset: card

::selection
    color: $black
    background: $blue

.card:not(#back-to-top)
    position: relative
    counter-increment: card

    &, .card-content
        undercover-before()

    &:before
        top: -1.2px
        left: -1.2px
        right: -1.2px
        bottom: -1.2px
        background-color: $blue
        cut-corner-reverse(16px)

    &:after
        content: 'R' counter(card)
        position: absolute
        color: $blue
        right: 2rem
        bottom: -.6em
        font-size: .75rem
        padding: 0 .25em
        background: $body-background-color

    .card-image
        cut-corner-top-right(16px)

    .card-content:before
        background-color: $body-background-color
        cut-corner-reverse(16px)

    .card-image + .card-content:before
        cut-corner-bottom-left(16px)

clip-button($color, $color-invert)
    &:before
        background-color: $color
        color: $color-invert

    &:hover:before, &.is-hovered:before
        background-color: darken($color, 2.5%)
        color: $color-invert

    &:focus:before, &.is-focused:before
        color: $color-invert

    &:active:before, &.is-active:before
        background-color: darken($color, 5%)
        color: $color-invert

    &[disabled]:before, fieldset[disabled] &:before
        background-color: $color

    &.is-inverted
        &:before
            background-color: $color-invert
            color: $color

            &:hover:before, &.is-hovered:before
                background-color: darken($color-invert, 5%)

            &[disabled]:before, fieldset[disabled] &:before
                background-color: $color-invert
                border-color: transparent
                box-shadow: none
                color: $color

.button:not(input)
    border: none
    outline: none
    background: transparent !important
    undercover-before()

    &:before
        cut-corner(8px)

    // clip-path will cut off overflown content inside a button
    // thus we need to use :before pseudo-element to style the buttons
    for $name, $pair in $colors
        $color = $pair['1']
        $color-invert = $pair['2']

        &.is-{$name}
            clip-button($color, $color-invert)

.field.has-addons
    .control:not(:first-child)
        .button
            cut-corner-bottom-right(8px)

.menu-list a
    cut-corner(8px)

.tags.has-addons
    .tag:first-child
        background: $yellow !important

    .tag:last-child
        background: $blue !important

.pagination-previous, .pagination-next, .pagination-link
    cut-corner(8px)

    &:hover
        background-color: $blue

        &, a
            color: $black

.navbar-main
    padding-top: 10px
    padding-bottom: 30px

    &:after
        content: ''
        position: absolute
        left: 0
        right: 0
        bottom: -2px
        background: url('../img/razor-top-black.svg') repeat-x top
        height: 40px

    .navbar-menu
        .navbar-item
            &:hover, &.is-active
                color: $navbar-background-color
                background-color: $body-background-color !important

article.article, article.media
    .title a
        background-image: linear-gradient(transparent calc(100% - 2px), $text-strong 2px)
        background-repeat: no-repeat
        background-size: 0 100%
        transition: background-size .25s ease-in-out

    .title:hover a
        background-size: 100% 100%

article.article
    .article-more
        clip-button($info, $info-invert)

.article-licensing
    background: $black-ter

.content
    blockquote
        background: transparent
        border: .5px solid $blue
        border-left: 5px solid $blue

.footer
    position: relative

    &:before
        content: ''
        position: absolute
        left: 0
        right: 0
        top: -1px
        height: 39px
        background: url('../img/razor-bottom-black.svg') repeat-x top

    & > .container
        padding-top: 40px

.timeline .media
    &:before
        clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%)

.searchbox .searchbox-container
    border: 1px solid $blue

    .searchbox-body
        border-bottom: 1px solid $searchbox-border

        li:last-child .searchbox-result-section
            border-bottom: none

    .searchbox-result-item
        em
            color: $black

#back-to-top
    color: $black
    background: $blue
    margin-top: 45px
    cut-corner(8px)

.cc-window, .cc-revoke
    border-radius: 0 !important

.cc-window
    &:not(.cc-banner)
        border: 1px solid $blue

    &.cc-theme-classic, &.cc-theme-block
        .cc-compliance > .cc-btn
            border-radius: 0

    &.cc-banner
        .cc-compliance > .cc-btn
            background-color: $blue

            &:hover, &:focus
                background-color: darken($blue, 2.5%)


================================================
FILE: source/css/default.styl
================================================
@import 'style'


================================================
FILE: source/css/style.styl
================================================
// Base CSS framework
@import '../../include/style/base'
// Helper classes & mixins
@import '../../include/style/helper'
// Icarus components
@import '../../include/style/button'
@import '../../include/style/card'
@import '../../include/style/article'
@import '../../include/style/navbar'
@import '../../include/style/footer'
@import '../../include/style/pagination'
@import '../../include/style/timeline'
@import '../../include/style/search'
@import '../../include/style/codeblock'
@import '../../include/style/widget'
@import '../../include/style/donate'
@import '../../include/style/plugin'
@import '../../include/style/responsive'


================================================
FILE: source/js/.eslintrc.json
================================================
{
    "extends": "../../.eslintrc.json",
    "env": {
        "browser": true,
        "jquery": true,
        "node": false
    }
}

================================================
FILE: source/js/animation.js
================================================
(function() {
    function $() {
        return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
    }

    $('body > .navbar, body > .section, body > .footer').forEach(element => {
        element.style.transition = '0s';
        element.style.opacity = '0';
    });
    document.querySelector('body > .navbar').style.transform = 'translateY(-100px)';
    [
        '.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
        '.column-left > .card, .column-right-shadow > .card',
        '.column-right > .card'
    ].forEach(selector => {
        $(selector).forEach(element => {
            element.style.transition = '0s';
            element.style.opacity = '0';
            element.style.transform = 'scale(0.8)';
            element.style.transformOrigin = 'center top';
        });
    });
    // disable jump to location.hash
    if (window.location.hash) {
        window.scrollTo(0, 0);
        setTimeout(() => window.scrollTo(0, 0));
    }

    setTimeout(() => {
        $('body > .navbar, body > .section, body > .footer').forEach(element => {
            element.style.opacity = '1';
            element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
        });
        document.querySelector('body > .navbar').style.transform = 'translateY(0)';

        let i = 1;
        [
            '.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
            '.column-left > .card, .column-right-shadow > .card',
            '.column-right > .card'
        ].forEach(selector => {
            $(selector).forEach(element => {
                setTimeout(() => {
                    element.style.opacity = '1';
                    element.style.transform = '';
                    element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
                }, i * 100);
                i++;
            });
        });

        // jump to location.hash
        if (window.location.hash) {
            setTimeout(() => {
                const id = '#' + CSS.escape(window.location.hash.substring(1));
                const target = document.querySelector(id);
                if (target) {
                    target.scrollIntoView({ behavior: 'smooth' });
                }
            }, i * 100);
        }
    });
}());


================================================
FILE: source/js/back_to_top.js
================================================
$(document).ready(() => {
    const $button = $('#back-to-top');
    const $footer = $('footer.footer');
    const $mainColumn = $('.column-main');
    const $leftSidebar = $('.column-left');
    const $rightSidebar = $('.column-right');
    let lastScrollTop = 0;
    const rightMargin = 20;
    const bottomMargin = 20;
    let lastState = null;
    const state = {
        base: {
            classname: 'card has-text-centered',
            left: '',
            width: 64,
            bottom: bottomMargin
        }
    };
    state['desktop-hidden'] = Object.assign({}, state.base, {
        classname: state.base.classname + ' rise-up'
    });
    state['desktop-visible'] = Object.assign({}, state['desktop-hidden'], {
        classname: state['desktop-hidden'].classname + ' fade-in'
    });
    state['desktop-dock'] = Object.assign({}, state['desktop-visible'], {
        classname: state['desktop-visible'].classname + ' fade-in is-rounded',
        width: 40
    });
    state['mobile-hidden'] = Object.assign({}, state.base, {
        classname: state.base.classname + ' fade-in',
        right: rightMargin
    });
    state['mobile-visible'] = Object.assign({}, state['mobile-hidden'], {
        classname: state['mobile-hidden'].classname + ' rise-up'
    });

    function isStateEquals(prev, next) {
        return ![].concat(Object.keys(prev), Object.keys(next)).some(key => {
            return !Object.prototype.hasOwnProperty.call(prev, key)
                || !Object.prototype.hasOwnProperty.call(next, key)
                || next[key] !== prev[key];
        });
    }

    function applyState(state) {
        if (lastState !== null && isStateEquals(lastState, state)) {
            return;
        }
        $button.attr('class', state.classname);
        for (const prop in state) {
            if (prop === 'classname') {
                continue;
            }
            $button.css(prop, state[prop]);
        }
        lastState = state;
    }

    function isDesktop() {
        return window.innerWidth >= 1078;
    }

    function isTablet() {
        return window.innerWidth >= 768 && !isDesktop();
    }

    function isScrollUp() {
        return $(window).scrollTop() < lastScrollTop && $(window).scrollTop() > 0;
    }

    function hasLeftSidebar() {
        return $leftSidebar.length > 0;
    }

    function hasRightSidebar() {
        return $rightSidebar.length > 0;
    }

    function getRightSidebarBottom() {
        if (!hasRightSidebar()) {
            return 0;
        }
        return Math.max.apply(null, $rightSidebar.find('.widget').map(function() {
            return $(this).offset().top + $(this).outerHeight(true);
        }));
    }

    function getScrollTop() {
        return $(window).scrollTop();
    }

    function getScrollBottom() {
        return $(window).scrollTop() + $(window).height();
    }

    function getButtonWidth() {
        return $button.outerWidth(true);
    }

    function getButtonHeight() {
        return $button.outerHeight(true);
    }

    function updateScrollTop() {
        lastScrollTop = $(window).scrollTop();
    }

    function update() {
        // desktop mode or tablet mode with only right sidebar enabled
        if (isDesktop() || (isTablet() && !hasLeftSidebar() && hasRightSidebar())) {
            let nextState;
            const padding = ($mainColumn.outerWidth() - $mainColumn.width()) / 2;
            const maxLeft = $(window).width() - getButtonWidth() - rightMargin;
            const maxBottom = $footer.offset().top + (getButtonHeight() / 2) + bottomMargin;
            if (getScrollTop() === 0 || getScrollBottom() < getRightSidebarBottom() + padding + getButtonHeight()) {
                nextState = state['desktop-hidden'];
            } else if (getScrollBottom() < maxBottom) {
                nextState = state['desktop-visible'];
            } else {
                nextState = Object.assign({}, state['desktop-dock'], {
                    bottom: getScrollBottom() - maxBottom + bottomMargin
                });
            }

            const left = $mainColumn.offset().left + $mainColumn.outerWidth() + padding;
            nextState = Object.assign({}, nextState, {
                left: Math.min(left, maxLeft)
            });
            applyState(nextState);
        } else {
            // mobile and tablet mode
            if (!isScrollUp()) {
                applyState(state['mobile-hidden']);
            } else {
                applyState(state['mobile-visible']);
            }
            updateScrollTop();
        }
    }

    update();
    $(window).resize(update);
    $(window).scroll(update);

    $('#back-to-top').on('click', () => {
        if (CSS && CSS.supports && CSS.supports('(scroll-behavior: smooth)')) {
            window.scroll({ top: 0, behavior: 'smooth' });
        } else {
            $('body, html').animate({ scrollTop: 0 }, 400);
        }
    });
});


================================================
FILE: source/js/column.js
================================================
(function() {
    function $() {
        return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
    }

    // copy widgets in the right column, when exist, to the bottom of the left column
    if ($('.columns .column-right').length && $('.columns .column-right-shadow').length && !$('.columns .column-right-shadow')[0].children.length) {
        for (const child of $('.columns .column-right')[0].children) {
            $('.columns .column-right-shadow')[0].append(child.cloneNode(true));
        }
    }
}());


================================================
FILE: source/js/main.js
================================================
/* eslint-disable node/no-unsupported-features/node-builtins */
(function($, moment, ClipboardJS, config) {
    $('.article img:not(".not-gallery-item")').each(function() {
        // wrap images with link and add caption if possible
        if ($(this).parent('a').length === 0) {
            $(this).wrap('<a class="gallery-item" href="' + $(this).attr('src') + '"></a>');
            if (this.alt) {
                $(this).after('<p class="has-text-centered is-size-6 caption">' + this.alt + '</p>');
            }
        }
    });

    if (typeof $.fn.lightGallery === 'function') {
        $('.article').lightGallery({ selector: '.gallery-item' });
    }
    if (typeof $.fn.justifiedGallery === 'function') {
        if ($('.justified-gallery > p > .gallery-item').length) {
            $('.justified-gallery > p > .gallery-item').unwrap();
        }
        $('.justified-gallery').justifiedGallery();
    }

    if (typeof moment === 'function') {
        $('.article-meta time').each(function() {
            $(this).text(moment($(this).attr('datetime')).fromNow());
        });
    }

    $('.article > .content > table').each(function() {
        if ($(this).width() > $(this).parent().width()) {
            $(this).wrap('<div class="table-overflow"></div>');
        }
    });

    function adjustNavbar() {
        const navbarWidth = $('.navbar-main .navbar-start').outerWidth() + $('.navbar-main .navbar-end').outerWidth();
        if ($(document).outerWidth() < navbarWidth) {
            $('.navbar-main .navbar-menu').addClass('justify-content-start');
        } else {
            $('.navbar-main .navbar-menu').removeClass('justify-content-start');
        }
    }
    adjustNavbar();
    $(window).resize(adjustNavbar);

    function toggleFold(codeBlock, isFolded) {
        const $toggle = $(codeBlock).find('.fold i');
        !isFolded ? $(codeBlock).removeClass('folded') : $(codeBlock).addClass('folded');
        !isFolded ? $toggle.removeClass('fa-angle-right') : $toggle.removeClass('fa-angle-down');
        !isFolded ? $toggle.addClass('fa-angle-down') : $toggle.addClass('fa-angle-right');
    }

    function createFoldButton(fold) {
        return '<span class="fold">' + (fold === 'unfolded' ? '<i class="fas fa-angle-down"></i>' : '<i class="fas fa-angle-right"></i>') + '</span>';
    }

    $('figure.highlight table').wrap('<div class="highlight-body">');
    if (typeof config !== 'undefined'
        && typeof config.article !== 'undefined'
        && typeof config.article.highlight !== 'undefined') {

        $('figure.highlight').addClass('hljs');
        $('figure.highlight .code .line span').each(function() {
            const classes = $(this).attr('class').split(/\s+/);
            for (const cls of classes) {
                $(this).addClass('hljs-' + cls);
                $(this).removeClass(cls);
            }
        });


        const clipboard = config.article.highlight.clipboard;
        const fold = config.article.highlight.fold.trim();

        $('figure.highlight').each(function() {
            if ($(this).find('figcaption').length) {
                $(this).find('figcaption').addClass('level is-mobile');
                $(this).find('figcaption').append('<div class="level-left">');
                $(this).find('figcaption').append('<div class="level-right">');
                $(this).find('figcaption div.level-left').append($(this).find('figcaption').find('span'));
                $(this).find('figcaption div.level-right').append($(this).find('figcaption').find('a'));
            } else {
                if (clipboard || fold) {
                    $(this).prepend('<figcaption class="level is-mobile"><div class="level-left"></div><div class="level-right"></div></figcaption>');
                }
            }
        });

        if (typeof ClipboardJS !== 'undefined' && clipboard) {
            $('figure.highlight').each(function() {
                const id = 'code-' + Date.now() + (Math.random() * 1000 | 0);
                const button = '<a href="javascript:;" class="copy" title="Copy" data-clipboard-target="#' + id + ' .code"><i class="fas fa-copy"></i></a>';
                $(this).attr('id', id);
                $(this).find('figcaption div.level-right').append(button);
            });
 
Download .txt
gitextract_bspt8wyp/

├── .eslintignore
├── .eslintrc.json
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug反馈.md
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   ├── feature_request.md
│   │   └── 功能建议.md
│   ├── PULL_REQUEST_TEMPLATE/
│   │   └── pull_request_template.md
│   ├── dependabot.yml
│   ├── stale.yml
│   └── workflows/
│       ├── github-release.yml
│       ├── lint.yml
│       ├── npm-publish.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── include/
│   ├── config.js
│   ├── dependency.js
│   ├── migration/
│   │   ├── head.js
│   │   ├── v2_v3.js
│   │   ├── v3_v4.js
│   │   ├── v4_v5.js
│   │   └── v5_v5.1.js
│   ├── register.js
│   ├── schema/
│   │   ├── comment/
│   │   │   └── .gitkeep
│   │   ├── common/
│   │   │   ├── article.json
│   │   │   ├── comment.json
│   │   │   ├── donates.json
│   │   │   ├── footer.json
│   │   │   ├── head.json
│   │   │   ├── navbar.json
│   │   │   ├── plugins.json
│   │   │   ├── providers.json
│   │   │   ├── search.json
│   │   │   ├── share.json
│   │   │   ├── sidebar.json
│   │   │   └── widgets.json
│   │   ├── config.json
│   │   ├── donate/
│   │   │   └── .gitkeep
│   │   ├── misc/
│   │   │   └── .gitkeep
│   │   ├── plugin/
│   │   │   ├── animejs.json
│   │   │   ├── back_to_top.json
│   │   │   └── pjax.json
│   │   ├── search/
│   │   │   └── .gitkeep
│   │   ├── share/
│   │   │   └── .gitkeep
│   │   └── widget/
│   │       └── profile.json
│   ├── style/
│   │   ├── article.styl
│   │   ├── base.styl
│   │   ├── button.styl
│   │   ├── card.styl
│   │   ├── codeblock.styl
│   │   ├── donate.styl
│   │   ├── footer.styl
│   │   ├── helper.styl
│   │   ├── navbar.styl
│   │   ├── pagination.styl
│   │   ├── plugin.styl
│   │   ├── responsive.styl
│   │   ├── search.styl
│   │   ├── timeline.styl
│   │   └── widget.styl
│   └── util/
│       └── console.js
├── languages/
│   ├── de.yml
│   ├── en.yml
│   ├── es.yml
│   ├── fr.yml
│   ├── id.yml
│   ├── it.yml
│   ├── ja.yml
│   ├── ko.yml
│   ├── pl.yml
│   ├── pt-BR.yml
│   ├── ru.yml
│   ├── sv.yml
│   ├── tk.yml
│   ├── tr.yml
│   ├── vn.yml
│   ├── zh-CN.yml
│   └── zh-TW.yml
├── layout/
│   ├── archive.jsx
│   ├── categories.jsx
│   ├── category.jsx
│   ├── comment/
│   │   └── .gitkeep
│   ├── common/
│   │   ├── article.jsx
│   │   ├── comment.jsx
│   │   ├── donates.jsx
│   │   ├── footer.jsx
│   │   ├── head.jsx
│   │   ├── navbar.jsx
│   │   ├── plugins.jsx
│   │   ├── scripts.jsx
│   │   ├── search.jsx
│   │   ├── share.jsx
│   │   └── widgets.jsx
│   ├── donate/
│   │   └── .gitkeep
│   ├── index.jsx
│   ├── layout.jsx
│   ├── misc/
│   │   └── .gitkeep
│   ├── page.jsx
│   ├── plugin/
│   │   ├── animejs.jsx
│   │   ├── back_to_top.jsx
│   │   └── pjax.jsx
│   ├── post.jsx
│   ├── search/
│   │   └── .gitkeep
│   ├── share/
│   │   └── .gitkeep
│   ├── tag.jsx
│   ├── tags.jsx
│   └── widget/
│       └── profile.jsx
├── package.json
├── scripts/
│   └── index.js
└── source/
    ├── css/
    │   ├── cyberpunk.styl
    │   ├── default.styl
    │   └── style.styl
    └── js/
        ├── .eslintrc.json
        ├── animation.js
        ├── back_to_top.js
        ├── column.js
        ├── main.js
        └── pjax.js
Download .txt
SYMBOL INDEX (76 symbols across 35 files)

FILE: include/config.js
  function loadThemeConfig (line 14) | function loadThemeConfig(hexo, cfgPaths) {
  function generateThemeConfigFile (line 20) | function generateThemeConfigFile(schema, cfgPath) {
  function hashConfigFile (line 25) | function hashConfigFile(cfgPath) {
  function checkConfig (line 30) | function checkConfig(hexo) {

FILE: include/dependency.js
  function checkDependency (line 10) | function checkDependency(name, reqVer) {

FILE: include/migration/v2_v3.js
  method constructor (line 8) | constructor() {
  method upgrade (line 12) | upgrade(config) {

FILE: include/migration/v3_v4.js
  method constructor (line 4) | constructor() {
  method upgrade (line 8) | upgrade(config) {

FILE: include/migration/v4_v5.js
  method constructor (line 4) | constructor() {
  method upgrade (line 8) | upgrade(config) {

FILE: include/migration/v5_v5.1.js
  method constructor (line 4) | constructor() {
  method upgrade (line 8) | upgrade(config) {

FILE: include/util/console.js
  method get (line 7) | get(obj, prop) {

FILE: layout/archive.jsx
  method render (line 8) | render() {

FILE: layout/categories.jsx
  method render (line 5) | render() {

FILE: layout/category.jsx
  method render (line 5) | render() {

FILE: layout/common/article.jsx
  function getWordCount (line 12) | function getWordCount(content) {
  method url_for (line 68) | url_for(category.path)}>{category.name}
  method url_for (line 102) | url_for(tag.path)}>{tag.name}

FILE: layout/common/comment.jsx
  method render (line 8) | render() {

FILE: layout/common/donates.jsx
  method render (line 8) | render() {

FILE: layout/common/head.jsx
  function getPageTitle (line 8) | function getPageTitle(page, siteTitle, helper) {
  method render (line 32) | render() {

FILE: layout/common/navbar.jsx
  function isSameLink (line 5) | function isSameLink(a, b) {
  class Navbar (line 16) | class Navbar extends Component {
    method render (line 17) | render() {

FILE: layout/common/plugins.jsx
  method render (line 8) | render() {

FILE: layout/common/scripts.jsx
  method render (line 6) | render() {

FILE: layout/common/search.jsx
  method render (line 8) | render() {

FILE: layout/common/share.jsx
  method render (line 8) | render() {

FILE: layout/common/widgets.jsx
  function formatWidgets (line 8) | function formatWidgets(widgets) {
  function hasColumn (line 24) | function hasColumn(widgets, position, config, page) {
  function getColumnCount (line 37) | function getColumnCount(widgets, config, page) {
  function getColumnSizeClass (line 41) | function getColumnSizeClass(columnCount) {
  function getColumnVisibilityClass (line 51) | function getColumnVisibilityClass(columnCount, position) {
  function getColumnOrderClass (line 58) | function getColumnOrderClass(position) {
  function isColumnSticky (line 62) | function isColumnSticky(config, position) {
  class Widgets (line 68) | class Widgets extends Component {
    method render (line 69) | render() {

FILE: layout/index.jsx
  method render (line 6) | render() {

FILE: layout/layout.jsx
  method render (line 11) | render() {

FILE: layout/page.jsx
  method render (line 5) | render() {

FILE: layout/plugin/animejs.jsx
  class AnimeJs (line 4) | class AnimeJs extends Component {
    method render (line 5) | render() {

FILE: layout/plugin/back_to_top.jsx
  class BackToTop (line 4) | class BackToTop extends Component {
    method render (line 5) | render() {

FILE: layout/plugin/pjax.jsx
  class Pjax (line 3) | class Pjax extends Component {
    method render (line 4) | render() {

FILE: layout/post.jsx
  method render (line 5) | render() {

FILE: layout/tag.jsx
  method render (line 5) | render() {

FILE: layout/tags.jsx
  method render (line 5) | render() {

FILE: layout/widget/profile.jsx
  class Profile (line 5) | class Profile extends Component {
    method renderSocialLinks (line 6) | renderSocialLinks(links) {
  function getAvatar (line 98) | function getAvatar() {

FILE: source/js/animation.js
  function $ (line 2) | function $() {

FILE: source/js/back_to_top.js
  function isStateEquals (line 37) | function isStateEquals(prev, next) {
  function applyState (line 45) | function applyState(state) {
  function isDesktop (line 59) | function isDesktop() {
  function isTablet (line 63) | function isTablet() {
  function isScrollUp (line 67) | function isScrollUp() {
  function hasLeftSidebar (line 71) | function hasLeftSidebar() {
  function hasRightSidebar (line 75) | function hasRightSidebar() {
  function getRightSidebarBottom (line 79) | function getRightSidebarBottom() {
  function getScrollTop (line 88) | function getScrollTop() {
  function getScrollBottom (line 92) | function getScrollBottom() {
  function getButtonWidth (line 96) | function getButtonWidth() {
  function getButtonHeight (line 100) | function getButtonHeight() {
  function updateScrollTop (line 104) | function updateScrollTop() {
  function update (line 108) | function update() {

FILE: source/js/column.js
  function $ (line 2) | function $() {

FILE: source/js/main.js
  function adjustNavbar (line 35) | function adjustNavbar() {
  function toggleFold (line 46) | function toggleFold(codeBlock, isFolded) {
  function createFoldButton (line 53) | function createFoldButton(fold) {
  function toggleToc (line 130) | function toggleToc() { // eslint-disable-line no-inner-declarations

FILE: source/js/pjax.js
  function initPjax (line 5) | function initPjax() {
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (202K chars).
[
  {
    "path": ".eslintignore",
    "chars": 13,
    "preview": "node_modules/"
  },
  {
    "path": ".eslintrc.json",
    "chars": 1063,
    "preview": "{\n  \"extends\": [\n    \"hexo\",\n    \"plugin:react/recommended\",\n    \"plugin:json/recommended\"\n  ],\n  \"settings\": {\n    \"nod"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Bug反馈.md",
    "chars": 827,
    "preview": "---\nname: Bug反馈\nabout: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。\ntitle: [Bug] 问题概述\nlabels: ''\nassignees: ''\n\n---\n\n> 确保你在提交Bug反馈之前仔"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1395,
    "preview": "---\nname: Bug Report\nabout: Please follow this template if you are reporting a bug, or your issue may be closed without "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 1075,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: GitHub Discussions\n    url: https://github.com/ppoffice/hexo-theme-"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 1022,
    "preview": "---\nname: Feature Request\nabout: Please follow this template if you are requesting a new feature, or your issue may be c"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/功能建议.md",
    "chars": 539,
    "preview": "---\nname: 功能建议\nabout: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。\ntitle: [FEAT] 功能建议概述\nlabels: ''\nassignees: ''\n\n---\n\n> 确保你在提交功能建议之前仔"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
    "chars": 1189,
    "preview": "---\nname: Pull Request\nabout: Suggest a code change to this project.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Note 0**"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 106,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: 'npm'\n    directory: '/'\n    schedule:\n      interval: 'daily'\n"
  },
  {
    "path": ".github/stale.yml",
    "chars": 935,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 14\n# Number of days of inactivity before a "
  },
  {
    "path": ".github/workflows/github-release.yml",
    "chars": 357,
    "preview": "name: GitHub Release\n\non:\n  push:\n    tags:\n      - '*'\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    permissions:\n  "
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 264,
    "preview": "name: Code Linting\n\non: [push, pull_request]\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/"
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "chars": 370,
    "preview": "name: Node.js Package\n\non:\n  release:\n    types: [published]\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n   "
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 1176,
    "preview": "name: Test\n\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-"
  },
  {
    "path": ".gitignore",
    "chars": 1759,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs."
  },
  {
    "path": ".npmignore",
    "chars": 60,
    "preview": ".github/\n.eslintignore\n.eslintrc.json\n.travis.yml\nyarn.lock\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1915,
    "preview": "# Contributing Guidelines\n\n## Code styles\n\nPlease refer to the [.eslintrc.json](https://github.com/ppoffice/hexo-theme-i"
  },
  {
    "path": "LICENSE",
    "chars": 1075,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2020 PPOffice\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "README.md",
    "chars": 5816,
    "preview": "<p align=\"center\" class=\"mb-2\">\n<img class=\"not-gallery-item\" height=\"48\" src=\"https://ppoffice.github.io/hexo-theme-ica"
  },
  {
    "path": "include/config.js",
    "chars": 5021,
    "preview": "/* eslint no-process-exit: \"off\" */\nconst fs = require('fs');\nconst path = require('path');\nconst util = require('util')"
  },
  {
    "path": "include/dependency.js",
    "chars": 1532,
    "preview": "/* eslint no-process-exit: \"off\" */\nconst semver = require('semver');\nconst createLogger = require('hexo-log');\nconst pa"
  },
  {
    "path": "include/migration/head.js",
    "chars": 39,
    "preview": "module.exports = require('./v5_v5.1');\n"
  },
  {
    "path": "include/migration/v2_v3.js",
    "chars": 3857,
    "preview": "const createLogger = require('hexo-log');\nconst deepmerge = require('deepmerge');\nconst Migration = require('hexo-compon"
  },
  {
    "path": "include/migration/v3_v4.js",
    "chars": 340,
    "preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
  },
  {
    "path": "include/migration/v4_v5.js",
    "chars": 235,
    "preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
  },
  {
    "path": "include/migration/v5_v5.1.js",
    "chars": 955,
    "preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
  },
  {
    "path": "include/register.js",
    "chars": 994,
    "preview": "const createLogger = require('hexo-log');\n\nconst logger = createLogger.default();\n\nmodule.exports = hexo => {\n    logger"
  },
  {
    "path": "include/schema/comment/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "include/schema/common/article.json",
    "chars": 2668,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/article.json\",\n    \"description\": \"Artic"
  },
  {
    "path": "include/schema/common/comment.json",
    "chars": 1106,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/comment.json\",\n    \"description\": \"Comme"
  },
  {
    "path": "include/schema/common/donates.json",
    "chars": 775,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/donates.json\",\n    \"description\": \"Donat"
  },
  {
    "path": "include/schema/common/footer.json",
    "chars": 1380,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/footer.json\",\n    \"description\": \"Page f"
  },
  {
    "path": "include/schema/common/head.json",
    "chars": 858,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/head.json\",\n    \"description\": \"Page met"
  },
  {
    "path": "include/schema/common/navbar.json",
    "chars": 1246,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/navbar.json\",\n    \"description\": \"Page t"
  },
  {
    "path": "include/schema/common/plugins.json",
    "chars": 1656,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/plugins.json\",\n    \"description\": \"Plugi"
  },
  {
    "path": "include/schema/common/providers.json",
    "chars": 929,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/providers.json\",\n    \"description\": \"CDN"
  },
  {
    "path": "include/schema/common/search.json",
    "chars": 518,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/search.json\",\n    \"description\": \"Search"
  },
  {
    "path": "include/schema/common/share.json",
    "chars": 576,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/share.json\",\n    \"description\": \"Share p"
  },
  {
    "path": "include/schema/common/sidebar.json",
    "chars": 1021,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/sidebar.json\",\n    \"description\": \"Sideb"
  },
  {
    "path": "include/schema/common/widgets.json",
    "chars": 1376,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/common/widgets.json\",\n    \"description\": \"Sideb"
  },
  {
    "path": "include/schema/config.json",
    "chars": 2044,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/config.json\",\n    \"description\": \"The configura"
  },
  {
    "path": "include/schema/donate/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "include/schema/misc/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "include/schema/plugin/animejs.json",
    "chars": 192,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/plugin/animejs.json\",\n    \"description\": \"Enabl"
  },
  {
    "path": "include/schema/plugin/back_to_top.json",
    "chars": 197,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/plugin/back_to_top.json\",\n    \"description\": \"S"
  },
  {
    "path": "include/schema/plugin/pjax.json",
    "chars": 176,
    "preview": "{\r\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n    \"$id\": \"/plugin/pjax.json\",\r\n    \"description\": \"Enabl"
  },
  {
    "path": "include/schema/search/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "include/schema/share/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "include/schema/widget/profile.json",
    "chars": 2756,
    "preview": "{\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n    \"$id\": \"/widget/profile.json\",\n    \"description\": \"Profi"
  },
  {
    "path": "include/style/article.styl",
    "chars": 3977,
    "preview": "/* ---------------------------------\n *    Article Summary and Content\n * --------------------------------- */\n$article-"
  },
  {
    "path": "include/style/base.styl",
    "chars": 2506,
    "preview": "bulma-stylus-root = '../../../../node_modules/bulma-stylus/stylus'\n\n/* ---------------------------------\n *   Override B"
  },
  {
    "path": "include/style/button.styl",
    "chars": 217,
    "preview": "/* ---------------------------------\n *            Buttons\n * --------------------------------- */\n.button\n    &.is-tran"
  },
  {
    "path": "include/style/card.styl",
    "chars": 423,
    "preview": "/* ---------------------------------\n *              Card\n * --------------------------------- */\n.card\n    overflow: vi"
  },
  {
    "path": "include/style/codeblock.styl",
    "chars": 2144,
    "preview": "/* ---------------------------------\n *          Code Highlight\n * --------------------------------- */\n$codeblock-capti"
  },
  {
    "path": "include/style/donate.styl",
    "chars": 1448,
    "preview": "/* ---------------------------------\n *          Donate Buttons\n * --------------------------------- */\n$donate-qrcode-m"
  },
  {
    "path": "include/style/footer.styl",
    "chars": 425,
    "preview": "/* ---------------------------------\n *            Page Footer\n * --------------------------------- */\nfooter.footer\n   "
  },
  {
    "path": "include/style/helper.styl",
    "chars": 3021,
    "preview": "/* ---------------------------------\n *          Spacing helpers\n * --------------------------------- */\n$spacer ?= 1rem"
  },
  {
    "path": "include/style/navbar.styl",
    "chars": 1364,
    "preview": "/* ---------------------------------\n *           Top Navigation\n * --------------------------------- */\n$navbar-item-pa"
  },
  {
    "path": "include/style/pagination.styl",
    "chars": 867,
    "preview": "/* ---------------------------------\n *  Pagination and Post Navigation\n * --------------------------------- */\n$paginat"
  },
  {
    "path": "include/style/plugin.styl",
    "chars": 2995,
    "preview": "/* ---------------------------------\n *        Back to Top Button\n * --------------------------------- */\n#back-to-top\n "
  },
  {
    "path": "include/style/responsive.styl",
    "chars": 794,
    "preview": "/* ---------------------------------\n *         Responsive Layout\n * --------------------------------- */\n+widescreen()\n"
  },
  {
    "path": "include/style/search.styl",
    "chars": 5860,
    "preview": "/* ---------------------------------\n *           Search Box\n * --------------------------------- */\n// container sizes\n"
  },
  {
    "path": "include/style/timeline.styl",
    "chars": 1059,
    "preview": "/* ---------------------------------\n *          Archive Timeline\n * --------------------------------- */\n$timeline-fg-l"
  },
  {
    "path": "include/style/widget.styl",
    "chars": 1315,
    "preview": ".widget\n    .menu-list\n        li\n            ul\n                margin-right: 0\n\n        .level\n            margin-bott"
  },
  {
    "path": "include/util/console.js",
    "chars": 350,
    "preview": "let chalk;\ntry {\n    chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require\n} catch (e) { }\n\nmodule"
  },
  {
    "path": "languages/de.yml",
    "chars": 1702,
    "preview": "common:\n    archive:\n        one: 'Archiv'\n        other: 'Archive'\n    category:\n        one: 'Kategorie'\n        other"
  },
  {
    "path": "languages/en.yml",
    "chars": 1611,
    "preview": "common:\n    archive:\n        one: 'Archive'\n        other: 'Archives'\n    category:\n        one: 'Category'\n        othe"
  },
  {
    "path": "languages/es.yml",
    "chars": 1759,
    "preview": "#By SrWoOoW\ncommon:\n    archive:\n        one: 'Archivo'\n        other: 'Archivos'\n    category:\n        one: 'Categoría'"
  },
  {
    "path": "languages/fr.yml",
    "chars": 1760,
    "preview": "common:\n    archive:\n        one: 'Archive'\n        other: 'Archives'\n    category:\n        one: 'Catégorie'\n        oth"
  },
  {
    "path": "languages/id.yml",
    "chars": 1714,
    "preview": "common:\n    archive:\n        one: 'Arsip'\n        other: 'Arsip'\n    category:\n        one: 'Kategori'\n        other: 'K"
  },
  {
    "path": "languages/it.yml",
    "chars": 1701,
    "preview": "common:\n    archive:\n        one: 'Archivio'\n        other: 'Archivi'\n    category:\n        one: 'Categoria'\n        oth"
  },
  {
    "path": "languages/ja.yml",
    "chars": 1398,
    "preview": "common:\n    archive:\n        one: 'アーカイブ'\n        other: 'アーカイブ'\n    category:\n        one: 'カテゴリ'\n        other: 'カテゴリ'"
  },
  {
    "path": "languages/ko.yml",
    "chars": 1425,
    "preview": "common:\n    archive:\n        one: '아카이브'\n        other: '아카이브'\n    category:\n        one: '카테고리'\n        other: '카테고리'\n "
  },
  {
    "path": "languages/pl.yml",
    "chars": 1733,
    "preview": "common:\n    archive:\n        one: 'Archiwum'\n        other: 'Archiwum'\n    category:\n        one: 'Kategoria'\n        ot"
  },
  {
    "path": "languages/pt-BR.yml",
    "chars": 1686,
    "preview": "common:\n    archive:\n        one: 'Arquivo'\n        other: 'Arquivos'\n    category:\n        one: 'Categoria'\n        oth"
  },
  {
    "path": "languages/ru.yml",
    "chars": 1726,
    "preview": "common:\n    archive:\n        one: 'архив'\n        other: 'архивы'\n    category:\n        one: 'категории'\n        other: "
  },
  {
    "path": "languages/sv.yml",
    "chars": 1693,
    "preview": "common:\n    archive:\n        one: 'Arkiv'\n        other: 'Arkiv'\n    category:\n        one: 'Kategori'\n        other: 'K"
  },
  {
    "path": "languages/tk.yml",
    "chars": 1580,
    "preview": "common:\n    archive:\n        one: 'Arhiw'\n        other: 'Arhiwler'\n    category:\n        one: 'Bölüm'\n        other: 'B"
  },
  {
    "path": "languages/tr.yml",
    "chars": 1718,
    "preview": "common:\n    archive:\n        one: 'Arşiv'\n        other: 'Arşivler'\n    category:\n        one: 'Kategori'\n        other:"
  },
  {
    "path": "languages/vn.yml",
    "chars": 1655,
    "preview": "common:\n    archive:\n        one: 'Lưu trữ'\n        other: 'Lưu trữ'\n    category:\n        one: 'Thể loại'\n        other"
  },
  {
    "path": "languages/zh-CN.yml",
    "chars": 1273,
    "preview": "common:\n    archive:\n        one: '归档'\n        other: '归档'\n    category:\n        one: '分类'\n        other: '分类'\n    tag:\n"
  },
  {
    "path": "languages/zh-TW.yml",
    "chars": 1285,
    "preview": "common:\n    archive:\n        one: '彙整'\n        other: '彙整'\n    category:\n        one: '分類'\n        other: '分類'\n    tag:\n"
  },
  {
    "path": "layout/archive.jsx",
    "chars": 2733,
    "preview": "const moment = require('moment');\nconst { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require"
  },
  {
    "path": "layout/categories.jsx",
    "chars": 324,
    "preview": "const { Component } = require('inferno');\nconst Categories = require('hexo-component-inferno/lib/view/widget/categories'"
  },
  {
    "path": "layout/category.jsx",
    "chars": 1043,
    "preview": "const { Component, Fragment } = require('inferno');\nconst Index = require('./index');\n\nmodule.exports = class extends Co"
  },
  {
    "path": "layout/comment/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "layout/common/article.jsx",
    "chars": 8188,
    "preview": "const moment = require('moment');\nconst { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require"
  },
  {
    "path": "layout/common/comment.jsx",
    "chars": 1178,
    "preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
  },
  {
    "path": "layout/common/donates.jsx",
    "chars": 1412,
    "preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
  },
  {
    "path": "layout/common/footer.jsx",
    "chars": 3651,
    "preview": "const { Component } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/cache');\n\n"
  },
  {
    "path": "layout/common/head.jsx",
    "chars": 8256,
    "preview": "const { Component } = require('inferno');\nconst MetaTags = require('hexo-component-inferno/lib/view/misc/meta');\nconst W"
  },
  {
    "path": "layout/common/navbar.jsx",
    "chars": 4414,
    "preview": "const { Component, Fragment } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/"
  },
  {
    "path": "layout/common/plugins.jsx",
    "chars": 1054,
    "preview": "const createLogger = require('hexo-log');\nconst { Component, Fragment } = require('inferno');\nconst view = require('hexo"
  },
  {
    "path": "layout/common/scripts.jsx",
    "chars": 1833,
    "preview": "const { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require('hexo/dist/plugins/helper/date');"
  },
  {
    "path": "layout/common/search.jsx",
    "chars": 779,
    "preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
  },
  {
    "path": "layout/common/share.jsx",
    "chars": 789,
    "preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
  },
  {
    "path": "layout/common/widgets.jsx",
    "chars": 3815,
    "preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
  },
  {
    "path": "layout/donate/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "layout/index.jsx",
    "chars": 822,
    "preview": "const { Component, Fragment } = require('inferno');\nconst Paginator = require('hexo-component-inferno/lib/view/misc/pagi"
  },
  {
    "path": "layout/layout.jsx",
    "chars": 2146,
    "preview": "const { Component } = require('inferno');\nconst classname = require('hexo-component-inferno/lib/util/classname');\nconst "
  },
  {
    "path": "layout/misc/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "layout/page.jsx",
    "chars": 295,
    "preview": "const { Component } = require('inferno');\nconst Article = require('./common/article');\n\nmodule.exports = class extends C"
  },
  {
    "path": "layout/plugin/animejs.jsx",
    "chars": 628,
    "preview": "const { Component } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/cache');\n\n"
  },
  {
    "path": "layout/plugin/back_to_top.jsx",
    "chars": 785,
    "preview": "const { Component, Fragment } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/"
  },
  {
    "path": "layout/plugin/pjax.jsx",
    "chars": 456,
    "preview": "const { Component, Fragment } = require('inferno');\n\nclass Pjax extends Component {\n    render() {\n        if (this.prop"
  },
  {
    "path": "layout/post.jsx",
    "chars": 295,
    "preview": "const { Component } = require('inferno');\nconst Article = require('./common/article');\n\nmodule.exports = class extends C"
  },
  {
    "path": "layout/search/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "layout/share/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "layout/tag.jsx",
    "chars": 833,
    "preview": "const { Component, Fragment } = require('inferno');\nconst Index = require('./index');\n\nmodule.exports = class extends Co"
  },
  {
    "path": "layout/tags.jsx",
    "chars": 288,
    "preview": "const { Component } = require('inferno');\nconst Tags = require('hexo-component-inferno/lib/view/widget/tags');\n\nmodule.e"
  },
  {
    "path": "layout/widget/profile.jsx",
    "chars": 5711,
    "preview": "const { Component } = require('inferno');\nconst gravatrHelper = require('hexo-util').gravatar;\nconst { cacheComponent } "
  },
  {
    "path": "package.json",
    "chars": 1172,
    "preview": "{\n  \"name\": \"hexo-theme-icarus\",\n  \"version\": \"6.1.1\",\n  \"author\": \"ppoffice <ppoffice@users.noreply.github.com>\",\n  \"li"
  },
  {
    "path": "scripts/index.js",
    "chars": 814,
    "preview": "/* global hexo */\nconst createLogger = require('hexo-log');\n\nconst logger = createLogger.default();\n\n/**\n * Print welcom"
  },
  {
    "path": "source/css/cyberpunk.styl",
    "chars": 7943,
    "preview": "$family-sans-serif ?= 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif\n$family-code ?= 'Roboto Mono"
  },
  {
    "path": "source/css/default.styl",
    "chars": 16,
    "preview": "@import 'style'\n"
  },
  {
    "path": "source/css/style.styl",
    "chars": 635,
    "preview": "// Base CSS framework\n@import '../../include/style/base'\n// Helper classes & mixins\n@import '../../include/style/helper'"
  },
  {
    "path": "source/js/.eslintrc.json",
    "chars": 132,
    "preview": "{\n    \"extends\": \"../../.eslintrc.json\",\n    \"env\": {\n        \"browser\": true,\n        \"jquery\": true,\n        \"node\": f"
  },
  {
    "path": "source/js/animation.js",
    "chars": 2370,
    "preview": "(function() {\n    function $() {\n        return Array.prototype.slice.call(document.querySelectorAll.apply(document, arg"
  },
  {
    "path": "source/js/back_to_top.js",
    "chars": 4938,
    "preview": "$(document).ready(() => {\n    const $button = $('#back-to-top');\n    const $footer = $('footer.footer');\n    const $main"
  },
  {
    "path": "source/js/column.js",
    "chars": 546,
    "preview": "(function() {\n    function $() {\n        return Array.prototype.slice.call(document.querySelectorAll.apply(document, arg"
  },
  {
    "path": "source/js/main.js",
    "chars": 6035,
    "preview": "/* eslint-disable node/no-unsupported-features/node-builtins */\n(function($, moment, ClipboardJS, config) {\n    $('.arti"
  },
  {
    "path": "source/js/pjax.js",
    "chars": 1762,
    "preview": "(function() {\n    // eslint-disable-next-line no-unused-vars\n    let pjax;\n\n    function initPjax() {\n        try {\n    "
  }
]

About this extraction

This page contains the full source code of the ppoffice/hexo-theme-icarus GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (183.3 KB), approximately 49.3k tokens, and a symbol index with 76 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!