The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .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
    ├── img
        ├── avatar.png
        ├── favicon.svg
        ├── logo.svg
        ├── og_image.png
        ├── razor-bottom-black.svg
        └── razor-top-black.svg
    └── js
        ├── .eslintrc.json
        ├── animation.js
        ├── back_to_top.js
        ├── column.js
        ├── main.js
        └── pjax.js


/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/


--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": [
 3 |     "hexo",
 4 |     "plugin:react/recommended",
 5 |     "plugin:json/recommended"
 6 |   ],
 7 |   "settings": {
 8 |     "node": {
 9 |       "tryExtensions": [
10 |         ".js",
11 |         ".jsx",
12 |         ".json"
13 |       ]
14 |     },
15 |     "react": {
16 |       "version": "16.0"
17 |     }
18 |   },
19 |   "parserOptions": {
20 |     "ecmaFeatures": {
21 |       "jsx": true
22 |     },
23 |     "sourceType": "module",
24 |     "ecmaVersion": "latest"
25 |   },
26 |   "plugins": [
27 |     "react"
28 |   ],
29 |   "rules": {
30 |     "react/jsx-uses-vars": "error",
31 |     "indent": [
32 |       "error",
33 |       4,
34 |       {
35 |         "SwitchCase": 1
36 |       }
37 |     ],
38 |     "react/no-unknown-property": [
39 |       "error",
40 |       {
41 |         "ignore": [
42 |           "class",
43 |           "onclick",
44 |           "onload",
45 |           "onsubmit",
46 |           "crossorigin"
47 |         ]
48 |       }
49 |     ],
50 |     "react/react-in-jsx-scope": [
51 |       "off"
52 |     ],
53 |     "react/prop-types": [
54 |       "off"
55 |     ],
56 |     "react/display-name": [
57 |       "off"
58 |     ],
59 |     "react/jsx-key": [
60 |       "off"
61 |     ],
62 |     "react/jsx-no-target-blank": [
63 |       "error",
64 |       {
65 |         "allowReferrer": true
66 |       }
67 |     ]
68 |   }
69 | }


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Bug反馈.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Bug反馈
 3 | about: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。
 4 | title: [Bug] 问题概述
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | > 确保你在提交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)来了解你的问题是否已经被他人提出过。
11 | 
12 | **Bug描述**
13 | 简洁清晰地描述你遇到的Bug是什么。
14 | 
15 | **系统与环境**
16 | 列出你的Hexo和Icarus的版本和配置。
17 | 
18 | - Hexo,操作系统,和Node.js的版本(使用`hexo version`命令来查看)
19 | - 站点配置文件`_config.yml`
20 | - 主题配置文件`_config.icarus.yml`或`themes/icarus/_config.yml`
21 | - 其他额外的配置文件(文章front-matter,`_config.post.yml`,或`_config.page.yml`)
22 | - 浏览器版本(如Firefox 70.0,Chrome Android 80.0)
23 | 
24 | **复现方式**
25 | 列出复现这个Bug的步骤,如:
26 | 
27 | 1. 访问‘...’
28 | 2. 点击’...‘
29 | 3. 下拉到‘...’
30 | 4. 出现‘...’的错误
31 | 
32 | **期望行为**
33 | 简洁清晰地描述没有这个情况下你期望得到的结果。
34 | 
35 | **截图**
36 | 如果可以的话,请附上几张截图来帮助说明你遇到的问题。
37 | 
38 | **额外上下文**
39 | 附上与问题有关的其他上下文信息。
40 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Bug Report
 3 | about: Please follow this template if you are reporting a bug, or your issue may be closed without further notice.
 4 | title: [Bug] Bug summary
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | > 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.
11 | 
12 | **Describe the bug**
13 | A clear and concise description of what the bug is.
14 | 
15 | **System and Environment**
16 | The version and configuration of Hexo and Icarus.
17 | 
18 | - Hexo, OS, and node version (use `hexo version` command to view these information)
19 | - Site configuration file `_config.yml`
20 | - Theme configuration file `_config.icarus.yml` or `themes/icarus/_config.yml`
21 | - Any additional theme configuration files (post front-matter, `_config.post.yml`, or `_config.page.yml`)
22 | - Browser and version (e.g., Firefox 70.0, Chrome Android 80.0)
23 | 
24 | **To Reproduce**
25 | Steps to reproduce the behavior, such as:
26 | 
27 | 1. Go to '...'
28 | 2. Click on '...'
29 | 3. Scroll down to '...'
30 | 4. '...' error appears
31 | 
32 | **Expected behavior**
33 | A clear and concise description of what you expected to happen.
34 | 
35 | **Screenshots**
36 | If applicable, add screenshots to help explain your problem.
37 | 
38 | **Additional context**
39 | Add any other context about the problem here.
40 | 


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


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Feature Request
 3 | about: Please follow this template if you are requesting a new feature, or your issue may be closed without further notice.
 4 | title: [FEAT] Feature request summary
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | > 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.
11 | 
12 | **Is your feature request related to a problem? Please describe.**
13 | 
14 | A clear and concise description of what the problem is (e.g., I'm always frustrated when [...]).
15 | 
16 | **Describe the solution you'd like**
17 | 
18 | A clear and concise description of what you want to happen.
19 | 
20 | **Describe alternatives you've considered**
21 | 
22 | A clear and concise description of any alternative solutions or features you've considered.
23 | 
24 | **Additional context**
25 | 
26 | Add any other context or screenshots about the feature request here.
27 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/功能建议.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: 功能建议
 3 | about: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。
 4 | title: [FEAT] 功能建议概述
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | > 确保你在提交功能建议之前仔细阅读了[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)来了解你的建议是否已经被他人提出过。
11 | 
12 | **你的功能建议与某个使用问题相关么?请详述。**
13 | 
14 | 简洁清晰地描述你遇到的问题是什么(如:我在使用...的时候遇到了...)。
15 | 
16 | **描述你想要的解决方案**
17 | 
18 | 简洁清晰地描述你想要的解决方案可以达到的效果。
19 | 
20 | **描述你考虑过的替代办法**
21 | 
22 | 简洁清晰地描述你考虑过的替代解决方案或是新功能。
23 | 
24 | **额外上下文**
25 | 
26 | 附上与功能请求有关的其他上下文信息或者截图。
27 | 


--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Pull Request
 3 | about: Suggest a code change to this project.
 4 | title: ''
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | **Note 0**
11 | Please review [the contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) before making this pull request.
12 | 
13 | **Note 1**
14 | 
15 | Please break up your pull request into multiple smaller requests if it contains multiple bug fixes 
16 | or new features.
17 | Each pull request should have one bug fix or new feature only for better code maintainability.
18 | 
19 | **Note 2**
20 | 
21 | Many components of this theme, including core functions, some Hexo extensions, widgets and plugins, 
22 | have been moved to [ppoffice/hexo-component-inferno](https://github.com/ppoffice/hexo-component-inferno).
23 | Please make a pull request to that repository instead of this one if your changes are related to
24 | the above components.
25 | 
26 | **Detailed description**
27 | 
28 | > 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.
29 | 
30 | > 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.
31 | 


--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |   - package-ecosystem: 'npm'
4 |     directory: '/'
5 |     schedule:
6 |       interval: 'daily'
7 | 


--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
 1 | # Number of days of inactivity before an issue becomes stale
 2 | daysUntilStale: 14
 3 | # Number of days of inactivity before a stale issue is closed
 4 | daysUntilClose: 7
 5 | # Issues with these labels will never be considered stale
 6 | exemptLabels:
 7 |   - bug:core
 8 |   - bug:extension
 9 |   - bug:general
10 |   - feature:core
11 |   - feature:extension
12 |   - feature:general
13 |   - tutorial:v1
14 |   - tutorial:v2
15 |   - tutorial:v3
16 |   - tutorial:v4
17 |   - tutorial:v5
18 |   - tutorial:v6
19 |   - tutorial:v7
20 |   - tutorial:v8
21 |   - tutorial:v9
22 |   - Gitalk
23 |   - utterances
24 | # Label to use when marking an issue as stale
25 | staleLabel: wontfix
26 | # Comment to post when marking an issue as stale. Set to `false` to disable
27 | markComment: >
28 |   This issue has been automatically marked as stale because it has not had
29 |   recent activity. It will be closed if no further activity occurs. Thank you
30 |   for your contributions.
31 | # Comment to post when closing a stale issue. Set to `false` to disable
32 | closeComment: false


--------------------------------------------------------------------------------
/.github/workflows/github-release.yml:
--------------------------------------------------------------------------------
 1 | name: GitHub Release
 2 | 
 3 | on:
 4 |   push:
 5 |     tags:
 6 |       - '*'
 7 | 
 8 | jobs:
 9 |   publish:
10 |     runs-on: ubuntu-latest
11 |     permissions:
12 |       contents: write
13 |     steps:
14 |       - uses: actions/checkout@v3
15 |       - uses: ncipollo/release-action@v1
16 |         with:
17 |           tag: ${{ github.ref }}
18 |           name: ${{ github.ref }}
19 |           draft: true
20 |           prerelease: false
21 | 


--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
 1 | name: Code Linting
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | jobs:
 6 |   lint:
 7 |     runs-on: ubuntu-latest
 8 |     steps:
 9 |       - uses: actions/checkout@v3
10 |       - uses: actions/setup-node@v3
11 |         with:
12 |           node-version: latest
13 |       - run: npm install
14 |       - run: npm run lint
15 | 


--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
 1 | name: Node.js Package
 2 | 
 3 | on:
 4 |   release:
 5 |     types: [published]
 6 | 
 7 | jobs:
 8 |   publish:
 9 |     runs-on: ubuntu-latest
10 |     steps:
11 |       - uses: actions/checkout@v3
12 |       - uses: actions/setup-node@v3
13 |         with:
14 |           node-version: 14
15 |           registry-url: https://registry.npmjs.org/
16 |       - run: npm publish
17 |         env:
18 |           NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
19 | 


--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
 1 | name: Test
 2 | 
 3 | on: [push, pull_request]
 4 | 
 5 | jobs:
 6 |   test:
 7 |     runs-on: ubuntu-latest
 8 |     strategy:
 9 |       matrix:
10 |         node-version: [14, latest]
11 |       fail-fast: false
12 |     steps:
13 |       - uses: actions/checkout@v3
14 |         with:
15 |           repository: hexojs/hexo-starter
16 |           ref: dcd18588de8f5c1bcc689c101e2f21726c11c4d6  # pin blog dependencies to support node.js 14
17 |       - uses: actions/checkout@v3
18 |         with:
19 |           path: themes/icarus
20 |       - uses: actions/checkout@v3
21 |         with:
22 |           repository: SukkaLab/hexo-many-posts
23 |           path: source/_posts/hexo-many-posts
24 |       - uses: actions/setup-node@v3
25 |         with:
26 |           node-version: ${{ matrix.node-version }}
27 |       - uses: actions/cache@v3
28 |         with:
29 |           path: node_modules
30 |           key: npm-cache
31 |           restore-keys: npm-cache
32 |       - run: npm install
33 |       - run: >
34 |           npm install $(node -e "const deps=require('./themes/icarus/package.json').dependencies;
35 |           console.log(Object.keys(deps).map(key=>key+'@'+deps[key]).join(' '));")
36 |       - run: npm install hexo-tag-embed
37 |       - run: npx hexo config theme icarus
38 |       - run: time NODE_ENV=production npx hexo g -b
39 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
  1 | # Logs
  2 | logs
  3 | *.log
  4 | npm-debug.log*
  5 | yarn-debug.log*
  6 | yarn-error.log*
  7 | lerna-debug.log*
  8 | 
  9 | # Diagnostic reports (https://nodejs.org/api/report.html)
 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
 11 | 
 12 | # Runtime data
 13 | pids
 14 | *.pid
 15 | *.seed
 16 | *.pid.lock
 17 | 
 18 | # Directory for instrumented libs generated by jscoverage/JSCover
 19 | lib-cov
 20 | 
 21 | # Coverage directory used by tools like istanbul
 22 | coverage
 23 | *.lcov
 24 | 
 25 | # nyc test coverage
 26 | .nyc_output
 27 | 
 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
 29 | .grunt
 30 | 
 31 | # Bower dependency directory (https://bower.io/)
 32 | bower_components
 33 | 
 34 | # node-waf configuration
 35 | .lock-wscript
 36 | 
 37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
 38 | build/Release
 39 | 
 40 | # Dependency directories
 41 | node_modules/
 42 | jspm_packages/
 43 | 
 44 | # TypeScript v1 declaration files
 45 | typings/
 46 | 
 47 | # TypeScript cache
 48 | *.tsbuildinfo
 49 | 
 50 | # Optional npm cache directory
 51 | .npm
 52 | 
 53 | # Optional eslint cache
 54 | .eslintcache
 55 | 
 56 | # Microbundle cache
 57 | .rpt2_cache/
 58 | .rts2_cache_cjs/
 59 | .rts2_cache_es/
 60 | .rts2_cache_umd/
 61 | 
 62 | # Optional REPL history
 63 | .node_repl_history
 64 | 
 65 | # Output of 'npm pack'
 66 | *.tgz
 67 | 
 68 | # Yarn Integrity file
 69 | .yarn-integrity
 70 | 
 71 | # dotenv environment variables file
 72 | .env
 73 | .env.test
 74 | 
 75 | # parcel-bundler cache (https://parceljs.org/)
 76 | .cache
 77 | 
 78 | # Next.js build output
 79 | .next
 80 | 
 81 | # Nuxt.js build / generate output
 82 | .nuxt
 83 | dist
 84 | 
 85 | # Gatsby files
 86 | .cache/
 87 | # Comment in the public line in if your project uses Gatsby and not Next.js
 88 | # https://nextjs.org/blog/next-9-1#public-directory-support
 89 | # public
 90 | 
 91 | # vuepress build output
 92 | .vuepress/dist
 93 | 
 94 | # Serverless directories
 95 | .serverless/
 96 | 
 97 | # FuseBox cache
 98 | .fusebox/
 99 | 
100 | # DynamoDB Local files
101 | .dynamodb/
102 | 
103 | # TernJS port file
104 | .tern-port
105 | 
106 | # Stores VSCode versions used for testing VSCode extensions
107 | .vscode-test
108 | 
109 | _config*.yml*
110 | yarn.lock
111 | 
112 | # Intellij Idea config file
113 | .idea
114 | *.ipr
115 | *.iws
116 | *.iml


--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .github/
2 | .eslintignore
3 | .eslintrc.json
4 | .travis.yml
5 | yarn.lock
6 | 


--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
 1 | # Contributing Guidelines
 2 | 
 3 | ## Code styles
 4 | 
 5 | Please refer to the [.eslintrc.json](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.eslintrc.json).
 6 | You can also use `npm run lint` or `yarn lint` to fix code style issues.
 7 | 
 8 | ## Project versioning
 9 | 
10 | We use [SemVer](http://semver.org/) for versioning.
11 | Any changes to the code base should not be released using an existing version.
12 | 
13 | ## Commit message format
14 | 
15 | The commit message should follow the [Bluejava commit message format](https://github.com/bluejava/git-commit-guide).
16 | The supported scopes are:
17 | 
18 | - **core** for changes related to Hexo extensions and theme-specific functions
19 | - **comment** for comment plugin layout, schema, style, or script changes
20 | - **share** for share plugin layout, schema, style, or script changes
21 | - **donate** for donation plugin layout, schema, style, or script changes
22 | - **search** for search plugin layout, schema, style, or script changes
23 | - **widget** for widget layout, schema, style, or script changes
24 | - **plugin** for other plugin layout, schema, style, or script changes
25 | - **i18n** for adding or updating translations
26 | - **test** for testing or linting-related commits
27 | - **build** for build scripts, CI, other development or deployment related commits
28 | - use __\*__ or leave empty to refer to commits that do not have a clear scope
29 | 
30 | ## Submit changes
31 | 
32 | 1. Fork this repository, make changes to it, and run it against some actual Hexo sites to see if 
33 | anything is broken.
34 | You should also run `npm run lint` or `yarn lint` to find and fix any code formatting issue.
35 | 2. Submit a pull request to our repository. Please make sure you followed the instructions
36 | above.
37 | 3. We will review the pull request regularly and inform you of our questions and any changes 
38 | that need to be made before we can merge your pull request.
39 | 4. We expect your response within two weeks, after which your pull request may be closed if
40 | no activity is shown.
41 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2020 PPOffice
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | <p align="center" class="mb-2">
  2 | <img class="not-gallery-item" height="48" src="https://ppoffice.github.io/hexo-theme-icarus/img/logo.svg">
  3 | <br> A simple, delicate, and modern theme for the static site generator Hexo.
  4 | <br>
  5 | <a href="https://ppoffice.github.io/hexo-theme-icarus/">Preview</a> |
  6 | <a href="https://ppoffice.github.io/hexo-theme-icarus/categories/">Documentation</a> |
  7 | <a href="https://github.com/ppoffice/hexo-theme-icarus/discussions">Discuss on GitHub</a>
  8 | <br>
  9 | </p>
 10 | 
 11 | ![](https://ppoffice.github.io/hexo-theme-icarus/gallery/preview.png?1 "Icarus Preview")
 12 | 
 13 | ## :cd: Installation
 14 | 
 15 | ```shell
 16 | $ npm install hexo-theme-icarus
 17 | $ hexo config theme icarus
 18 | ```
 19 | 
 20 | Please refer to [Getting Started with Icarus](https://ppoffice.github.io/hexo-theme-icarus/uncategorized/getting-started-with-icarus/) 
 21 | for more details.
 22 | 
 23 | ## :gift: Features
 24 | 
 25 | ### Cyberpunk Theme Variant
 26 | 
 27 | Tap into the future cyber world with the newly added Cyberpunk theme variant.
 28 | Inspired by [Cyberpunk 2077](https://www.cyberpunk.net).
 29 | 
 30 | ![Icarus Cyberpunk](https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/cyberpunk.png "Icarus Cyberpunk")
 31 | 
 32 | ### Extensive Plugin Support
 33 | 
 34 | Icarus includes plentiful search, comment, sharing and other plugins out of the box that makes your
 35 | blog feature-rich and powerful.
 36 | 
 37 | **[Comment](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/)**
 38 | 
 39 | Changyan &middot; Disqus &middot; DisqusJS &middot; Facebook &middot; Gitalk &middot; Gitment &middot;
 40 | Isso &middot; LiveRe &middot; Utterance &middot; Valine
 41 | 
 42 | **[Donate Button](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/)**
 43 | 
 44 | Afdian.net &middot; Alipay &middot; Buy me a coffee &middot; Patreon &middot; Paypal &middot; Wecat
 45 | 
 46 | **[Search](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/)**
 47 | 
 48 | Algolia &middot; Baidu &middot; Google CSE &middot; Insight
 49 | 
 50 | **[Share](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/)**
 51 | 
 52 | AddThis &middot; AddToAny &middot; Baidu Share &middot; Share.js &middot; ShareThis
 53 | 
 54 | **[Widgets](https://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/)**
 55 | 
 56 | Google Adsense &middot; Archives &middot; Categories &middot; External Site Links &middot; 
 57 | Recent Posts &middot; Google Feedburner &middot; Tags &middot; Table of Contents
 58 | 
 59 | **[Analytics](https://ppoffice.github.io/hexo-theme-icarus/Plugins/Analytics/icarus-user-guide-web-analytics-plugins/)**
 60 | 
 61 | Baidu Statistics &middot; Bing Webmaster &middot; BuSuanZi Web Counter &middot; CNZZ Statistics &middot;
 62 | Google Analytics &middot; Hotjar &middot; StatCounter &middot; Twitter Conversion Tracking
 63 | 
 64 | **[Other Plugins](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/)**
 65 | 
 66 | Cookie Consent &middot; LightGallery &middot; Justified Gallery &middot; KaTeX &middot; MathJax &middot;
 67 | Oudated Browser &middot; Page Loading Animations
 68 | 
 69 | ### Colorful Code Highlight
 70 | 
 71 | Icarus directly import stylesheets from the [highlight.js](https://highlightjs.org/) package and makes more than
 72 | 90 code highlight themes available to you.
 73 | 
 74 | <table>
 75 |     <tr>
 76 |         <th>Atom One Light</th>
 77 |         <th>Monokai</th>
 78 |         <th>Kimbie Dark</th>
 79 |     </tr>
 80 |     <tr>
 81 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/atom-one-light.png?2"></td>
 82 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/monokai.png?2"></td>
 83 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/kimbie-dark.png?2"></td>
 84 |     </tr>
 85 | </table>
 86 | 
 87 | ### Flexible Theme Configuration
 88 | 
 89 | Icarus allows you to configure your site on a per-page or per-layout basis.
 90 | 
 91 | <div>
 92 | <table>
 93 |     <tr>
 94 |         <th>_config.yml</th>
 95 |         <th>post.md</th>
 96 |         <th>_config.page.yml</th>
 97 |     </tr>
 98 |     <tr>
 99 |         <td>
100 | <pre>widgets:
101 |   - type: profile
102 |     position: left
103 |   - type: recent_posts
104 |     position: right</pre>
105 |         </td>
106 |         <td>
107 | <pre>widgets:
108 |   - type: profile
109 |     position: left
110 |   - type: recent_posts
111 |     position: left</pre>
112 |         </td>
113 |         <td>
114 | <pre>widgets: null
115 |  
116 |  
117 |  
118 | </pre>
119 |         </td>
120 |     </tr>
121 |     <tr>
122 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/default-config.png"></td>
123 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/post-config.png"></td>
124 |         <td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/layout-config.png"></td>
125 |     </tr>
126 | </table>
127 | </div>
128 | 
129 | ### Responsive Layout
130 | 
131 | Give your audiences best viewing experience with Icarus's mobile-friendly responsive layout.
132 | 
133 | ![Responsive Layout](https://ppoffice.github.io/hexo-theme-icarus/gallery/responsive.png)
134 | 
135 | ## :hammer: Development
136 | 
137 | This project is built with
138 | 
139 | - [Hexo](https://hexo.io/)
140 | - [Inferno.js](https://infernojs.org/)
141 | - [Stylus](https://stylus-lang.com/)
142 | - [Bulma](https://bulma.io/)
143 | 
144 | Please refer to the [documentation](https://ppoffice.github.io/hexo-theme-icarus/categories/) and 
145 | [contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) for implementation details.
146 | 
147 | ## :tada: Contribute
148 | 
149 | If you feel like to help us build a better Icarus, you can
150 | 
151 | :black_nib: [Submit a tutorial](https://github.com/ppoffice/hexo-theme-icarus/new/site/source/_posts) |
152 | :earth_asia: [Add a translation](https://github.com/ppoffice/hexo-theme-icarus/tree/master/languages) |
153 | :triangular_flag_on_post: [Report a bug](https://github.com/ppoffice/hexo-theme-icarus/issues) |
154 | :electric_plug: [Suggest a new feature](https://github.com/ppoffice/hexo-theme-icarus/pulls)
155 | 
156 | ## :memo: License
157 | 
158 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/ppoffice/hexo-theme-icarus/blob/master/LICENSE) file for details.
159 | 


--------------------------------------------------------------------------------
/include/config.js:
--------------------------------------------------------------------------------
  1 | /* eslint no-process-exit: "off" */
  2 | const fs = require('fs');
  3 | const path = require('path');
  4 | const util = require('util');
  5 | const crypto = require('crypto');
  6 | const createLogger = require('hexo-log');
  7 | const yaml = require('hexo-component-inferno/lib/util/yaml');
  8 | const { Migrator } = require('hexo-component-inferno/lib/core/migrate');
  9 | const { SchemaLoader } = require('hexo-component-inferno/lib/core/schema');
 10 | const { yellow } = require('./util/console');
 11 | 
 12 | const logger = createLogger.default();
 13 | 
 14 | function loadThemeConfig(hexo, cfgPaths) {
 15 |     const configs = cfgPaths.map(cfgPath => fs.readFileSync(cfgPath))
 16 |         .map(cfgPath => yaml.parse(cfgPath));
 17 |     return Object.assign({}, ...configs, hexo.config.theme_config);
 18 | }
 19 | 
 20 | function generateThemeConfigFile(schema, cfgPath) {
 21 |     const defaultValue = schema.getDefaultValue();
 22 |     fs.writeFileSync(cfgPath, defaultValue.toYaml());
 23 | }
 24 | 
 25 | function hashConfigFile(cfgPath) {
 26 |     const content = fs.readFileSync(cfgPath);
 27 |     return crypto.createHash('md5').update(content).digest('hex');
 28 | }
 29 | 
 30 | function checkConfig(hexo) {
 31 |     if (!process.argv.includes('--icarus-dont-check-config')) {
 32 |         logger.info('=== Checking theme configurations ===');
 33 | 
 34 |         const siteCfgFile = path.join(hexo.base_dir, '_config.yml');
 35 |         const themeSiteCfg = path.join(hexo.base_dir, '_config.icarus.yml');
 36 |         const themeDirCfg = path.join(hexo.theme_dir, '_config.yml');
 37 |         const themeCfgPaths = [themeDirCfg, themeSiteCfg].filter(cfgPath => fs.existsSync(cfgPath));
 38 |         const themeSiteCfgExample = themeSiteCfg + '.example';
 39 | 
 40 |         const schemaDir = path.join(hexo.theme_dir, 'include/schema/');
 41 |         const loader = SchemaLoader.load(require(path.join(schemaDir, 'config.json')), schemaDir);
 42 |         const schema = loader.getSchema('/config.json');
 43 | 
 44 |         if (!process.argv.includes('--icarus-dont-generate-config')) {
 45 |             if (!themeCfgPaths.length) {
 46 |                 logger.warn('None of the following configuration files is found:');
 47 |                 logger.warn(`- ${yellow(themeSiteCfg)}`);
 48 |                 logger.warn(`- ${yellow(themeDirCfg)}`);
 49 |                 logger.info('Generating theme configuration file...');
 50 |                 generateThemeConfigFile(schema, themeSiteCfg);
 51 |                 themeCfgPaths.push(themeSiteCfg);
 52 |                 logger.info(`${yellow(themeSiteCfg)} created successfully.`);
 53 |                 logger.info('To skip configuration generation, use "--icarus-dont-generate-config".');
 54 |             }
 55 |         }
 56 | 
 57 |         let cfg = loadThemeConfig(hexo, themeCfgPaths);
 58 | 
 59 |         if (!process.argv.includes('--icarus-dont-upgrade-config')) {
 60 |             const migrator = new Migrator(require(path.join(hexo.theme_dir, 'include/migration/head')));
 61 |             if (cfg.version && migrator.isOudated(cfg.version)) {
 62 |                 logger.warn(`Your theme configuration is outdated (${cfg.version} < ${migrator.getLatestVersion()}).`);
 63 |                 logger.info('To skip the configuration upgrade, use "--icarus-dont-upgrade-config".');
 64 | 
 65 |                 logger.info('Backing up theme configuration files...');
 66 |                 for (const cfgPath of themeCfgPaths) {
 67 |                     const backupPath = cfgPath + '.' + hashConfigFile(cfgPath);
 68 |                     const relCfgPath = path.relative(hexo.base_dir, cfgPath);
 69 |                     const relBackupPath = path.relative(hexo.base_dir, backupPath);
 70 |                     fs.renameSync(cfgPath, backupPath);
 71 |                     logger.info(`${yellow(relCfgPath)} => ${yellow(relBackupPath)}`);
 72 |                 }
 73 | 
 74 |                 logger.info('Upgrading theme configurations...');
 75 |                 cfg = migrator.migrate(cfg);
 76 |                 fs.writeFileSync(themeSiteCfg, yaml.stringify(cfg));
 77 |                 logger.info(`Theme configurations are written to ${yellow(themeSiteCfg)}.`);
 78 | 
 79 |                 generateThemeConfigFile(schema, themeSiteCfgExample);
 80 |                 logger.info(`Example configurations is at ${yellow(themeSiteCfgExample)}.`);
 81 |             }
 82 |         }
 83 | 
 84 |         const validation = schema.validate(cfg);
 85 |         if (validation !== true) {
 86 |             logger.warn('Theme configurations failed one or more checks.');
 87 |             logger.warn('Icarus may still run, but you will encounter unexcepted results.');
 88 |             logger.warn('Here is some information for you to correct the configuration file.');
 89 |             logger.warn(util.inspect(validation));
 90 |         }
 91 | 
 92 |         const rootCfg = yaml.parse(fs.readFileSync(siteCfgFile));
 93 |         if (rootCfg.theme_config) {
 94 |             logger.warn(`"theme_config" found in ${yellow(siteCfgFile)}.`);
 95 |             logger.warn(`Please remove theme configurations from ${yellow(siteCfgFile)}.`);
 96 |         }
 97 |     }
 98 | }
 99 | 
100 | module.exports = hexo => {
101 |     try {
102 |         checkConfig(hexo);
103 |     } catch (e) {
104 |         logger.error(e);
105 |         logger.error('Theme configuration checking failed.');
106 |         logger.info('You may use \'--icarus-dont-check-config\' to skip configuration checking.');
107 |         process.exit(-1);
108 |     }
109 | };
110 | 


--------------------------------------------------------------------------------
/include/dependency.js:
--------------------------------------------------------------------------------
 1 | /* eslint no-process-exit: "off" */
 2 | const semver = require('semver');
 3 | const createLogger = require('hexo-log');
 4 | const packageInfo = require('../package.json');
 5 | const { yellow, red, green } = require('./util/console');
 6 | 
 7 | const logger = createLogger.default();
 8 | 
 9 | module.exports = hexo => {
10 |     function checkDependency(name, reqVer) {
11 |         try {
12 |             require.resolve(name);
13 |             const version = require(name + '/package.json').version;
14 |             if (!semver.satisfies(version, reqVer)) {
15 |                 logger.error(`Package ${yellow(name)}'s version (${yellow(version)}) does not satisfy the required version (${red(reqVer)}).`);
16 |                 return false;
17 |             }
18 |             return true;
19 |         } catch (e) {
20 |             logger.error(`Package ${yellow(name)} is not installed.`);
21 |         }
22 |         return false;
23 |     }
24 | 
25 |     logger.info('=== Checking package dependencies ===');
26 |     const dependencies = Object.assign({}, packageInfo.dependencies);
27 |     const missingDeps = Object.keys(dependencies)
28 |         .filter(name => !checkDependency(name, dependencies[name]));
29 |     if (missingDeps && missingDeps.length) {
30 |         logger.error('Please install the missing dependencies your Hexo site root directory:');
31 |         logger.error(green('npm install --save ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
32 |         logger.error('or:');
33 |         logger.error(green('yarn add ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
34 |         process.exit(-1);
35 |     }
36 | };
37 | 


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


--------------------------------------------------------------------------------
/include/migration/v2_v3.js:
--------------------------------------------------------------------------------
  1 | const createLogger = require('hexo-log');
  2 | const deepmerge = require('deepmerge');
  3 | const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
  4 | 
  5 | const logger = createLogger.default();
  6 | 
  7 | module.exports = class extends Migration {
  8 |     constructor() {
  9 |         super('3.0.0', null);
 10 |     }
 11 | 
 12 |     upgrade(config) {
 13 |         const result = deepmerge({}, config);
 14 |         result.head = {
 15 |             favicon: config.favicon || null,
 16 |             canonical_url: config.canonical_url || null,
 17 |             open_graph: config.open_graph || null,
 18 |             meta: config.meta || null,
 19 |             rss: config.rss || null
 20 |         };
 21 |         delete result.favicon;
 22 |         delete result.canonical_url;
 23 |         delete result.open_graph;
 24 |         delete result.meta;
 25 |         delete result.rss;
 26 | 
 27 |         if (result.logo === '/images/logo.svg') {
 28 |             result.logo = result.logo.replace(/^\/images/, '/img');
 29 |         }
 30 | 
 31 |         if (result.head.favicon === '/img/favicon.svg') {
 32 |             result.head.favicon = result.head.favicon.replace(/^\/images/, '/img');
 33 |         }
 34 | 
 35 |         if (result.search && Object.prototype.hasOwnProperty.call(result.search, 'type')) {
 36 |             switch (result.search.type) {
 37 |                 case 'google-cse':
 38 |                     result.search.type = 'google_cse';
 39 |                     break;
 40 |             }
 41 |         }
 42 | 
 43 |         if (result.comment && Object.prototype.hasOwnProperty.call(result.comment, 'type')) {
 44 |             switch (result.comment.type) {
 45 |                 case 'changyan':
 46 |                     result.comment.app_id = config.comment.appid;
 47 |                     delete result.comment.appid;
 48 |                     break;
 49 |             }
 50 |         }
 51 | 
 52 |         if (Array.isArray(result.donate) && result.donate.length) {
 53 |             result.donates = result.donate;
 54 |             delete result.donate;
 55 |         }
 56 | 
 57 |         if (Array.isArray(result.widgets) && result.widgets.length) {
 58 |             for (const widget of result.widgets) {
 59 |                 if (Object.prototype.hasOwnProperty.call(widget, 'type')) {
 60 |                     switch (widget.type) {
 61 |                         case 'archive':
 62 |                             widget.type = 'archives';
 63 |                             break;
 64 |                         case 'category':
 65 |                             widget.type = 'categories';
 66 |                             break;
 67 |                         case 'tag':
 68 |                             widget.type = 'tags';
 69 |                             break;
 70 |                         case 'tagcloud':
 71 |                             logger.warn('The tagcloud widget has been removed from Icarus in version 3.0.0.');
 72 |                             logger.warn('Please remove it from your configuration file.');
 73 |                             break;
 74 |                     }
 75 |                 }
 76 |             }
 77 |         }
 78 | 
 79 |         if (result.plugins && typeof result.plugins === 'object') {
 80 |             for (const name in result.plugins) {
 81 |                 switch (name) {
 82 |                     case 'outdated-browser':
 83 |                         result.plugins.outdated_browser = result.plugins[name];
 84 |                         delete result.plugins[name];
 85 |                         break;
 86 |                     case 'back-to-top':
 87 |                         result.plugins.back_to_top = result.plugins[name];
 88 |                         delete result.plugins[name];
 89 |                         break;
 90 |                     case 'baidu-analytics':
 91 |                         result.plugins.baidu_analytics = result.plugins[name];
 92 |                         delete result.plugins[name];
 93 |                         break;
 94 |                     case 'google-analytics':
 95 |                         result.plugins.google_analytics = result.plugins[name];
 96 |                         delete result.plugins[name];
 97 |                         break;
 98 |                 }
 99 |             }
100 |         }
101 | 
102 |         return result;
103 |     }
104 | };
105 | 


--------------------------------------------------------------------------------
/include/migration/v3_v4.js:
--------------------------------------------------------------------------------
 1 | const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
 2 | 
 3 | module.exports = class extends Migration {
 4 |     constructor() {
 5 |         super('4.0.0', null);
 6 |     }
 7 | 
 8 |     upgrade(config) {
 9 |         if (typeof config.article === 'object') {
10 |             delete config.article.thumbnail;
11 |         }
12 |         return config;
13 |     }
14 | };
15 | 


--------------------------------------------------------------------------------
/include/migration/v4_v5.js:
--------------------------------------------------------------------------------
 1 | const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
 2 | 
 3 | module.exports = class extends Migration {
 4 |     constructor() {
 5 |         super('5.0.0', null);
 6 |     }
 7 | 
 8 |     upgrade(config) {
 9 |         return config;
10 |     }
11 | };
12 | 


--------------------------------------------------------------------------------
/include/migration/v5_v5.1.js:
--------------------------------------------------------------------------------
 1 | const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
 2 | 
 3 | module.exports = class extends Migration {
 4 |     constructor() {
 5 |         super('5.1.0', null);
 6 |     }
 7 | 
 8 |     upgrade(config) {
 9 |         // Upgrade Waline configurations from v1 to v2.
10 |         const comment = config.comment || {};
11 |         const renamedOptions = {
12 |             'visitor': 'pageview',
13 |             'uploadImage': 'image_uploader',
14 |             'highlight': 'highlighter',
15 |             'math': 'tex_renderer'
16 |         };
17 |         if (comment.type === 'waline') {
18 |             for (const option in renamedOptions) {
19 |                 if (typeof comment[option] !== 'undefined') {
20 |                     if (typeof comment[renamedOptions[option]] === 'undefined') {
21 |                         comment[renamedOptions[option]] = comment[option];
22 |                     }
23 |                     delete comment[option];
24 |                 }
25 |             }
26 |         }
27 |         return config;
28 |     }
29 | };
30 | 


--------------------------------------------------------------------------------
/include/register.js:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | 
 3 | const logger = createLogger.default();
 4 | 
 5 | module.exports = hexo => {
 6 |     logger.info('=== Registering Hexo extensions ===');
 7 |     require('hexo-component-inferno/lib/hexo/filter/locals')(hexo);
 8 |     require('hexo-component-inferno/lib/hexo/generator/assets')(hexo);
 9 |     require('hexo-component-inferno/lib/hexo/generator/insight')(hexo);
10 |     require('hexo-component-inferno/lib/hexo/generator/categories')(hexo);
11 |     require('hexo-component-inferno/lib/hexo/generator/category')(hexo);
12 |     require('hexo-component-inferno/lib/hexo/generator/manifest')(hexo);
13 |     require('hexo-component-inferno/lib/hexo/generator/tags')(hexo);
14 |     require('hexo-component-inferno/lib/hexo/helper/cdn')(hexo);
15 |     require('hexo-component-inferno/lib/hexo/helper/page')(hexo);
16 |     require('hexo-component-inferno/lib/hexo/tag/message')(hexo);
17 |     require('hexo-component-inferno/lib/hexo/tag/tabs')(hexo);
18 |     require('hexo-component-inferno/lib/core/view').init(hexo);
19 | };
20 | 


--------------------------------------------------------------------------------
/include/schema/comment/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/include/schema/comment/.gitkeep


--------------------------------------------------------------------------------
/include/schema/common/article.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/article.json",
 4 |     "description": "Article related configurations",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "highlight": {
 8 |             "type": "object",
 9 |             "description": "Code highlight settings",
10 |             "properties": {
11 |                 "theme": {
12 |                     "type": "string",
13 |                     "description": "Code highlight themes\nhttps://github.com/highlightjs/highlight.js/tree/master/src/styles",
14 |                     "default": "atom-one-light",
15 |                     "nullable": true
16 |                 },
17 |                 "clipboard": {
18 |                     "type": "boolean",
19 |                     "description": "Show copy code button",
20 |                     "default": true,
21 |                     "nullable": true
22 |                 },
23 |                 "fold": {
24 |                     "type": "string",
25 |                     "description": "Default folding status of the code blocks. Can be \"\", \"folded\", \"unfolded\"",
26 |                     "enum": [
27 |                         "",
28 |                         "folded",
29 |                         "unfolded"
30 |                     ],
31 |                     "default": "unfolded",
32 |                     "nullable": true
33 |                 }
34 |             },
35 |             "nullable": true
36 |         },
37 |         "readtime": {
38 |             "type": "boolean",
39 |             "description": "Whether to show estimated article reading time",
40 |             "default": true,
41 |             "nullable": true
42 |         },
43 |         "update_time": {
44 |             "type": ["boolean", "string"],
45 |             "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",
46 |             "default": true,
47 |             "enum": [true, false, "auto"],
48 |             "nullable": true
49 |         },
50 |         "licenses": {
51 |             "$ref": "/misc/poly_links.json",
52 |             "description": "Article licensing block",
53 |             "examples": [
54 |                 {
55 |                     "Creative Commons": {
56 |                       "icon": "fab fa-creative-commons",
57 |                       "url": "https://creativecommons.org/"
58 |                     },
59 |                     "Attribution": {
60 |                       "icon": "fab fa-creative-commons-by",
61 |                       "url": "https://creativecommons.org/licenses/by/4.0/"
62 |                     },
63 |                     "Noncommercial": {
64 |                       "icon": "fab fa-creative-commons-nc",
65 |                       "url": "https://creativecommons.org/licenses/by-nc/4.0/"
66 |                     }
67 |                 }
68 |             ]
69 |         }
70 |     }
71 | }


--------------------------------------------------------------------------------
/include/schema/common/comment.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/comment.json",
 4 |     "description": "Comment plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/",
 5 |     "type": "object",
 6 |     "oneOf": [
 7 |         {
 8 |             "$ref": "/comment/disqus.json"
 9 |         },
10 |         {
11 |             "$ref": "/comment/changyan.json"
12 |         },
13 |         {
14 |             "$ref": "/comment/disqusjs.json"
15 |         },
16 |         {
17 |             "$ref": "/comment/facebook.json"
18 |         },
19 |         {
20 |             "$ref": "/comment/giscus.json"
21 |         },
22 |         {
23 |             "$ref": "/comment/gitalk.json"
24 |         },
25 |         {
26 |             "$ref": "/comment/gitment.json"
27 |         },
28 |         {
29 |             "$ref": "/comment/isso.json"
30 |         },
31 |         {
32 |             "$ref": "/comment/livere.json"
33 |         },
34 |         {
35 |             "$ref": "/comment/utterances.json"
36 |         },
37 |         {
38 |             "$ref": "/comment/valine.json"
39 |         },
40 |         {
41 |             "$ref": "/comment/waline.json"
42 |         },
43 |         {
44 |             "$ref": "/comment/twikoo.json"
45 |         }
46 |     ]
47 | }
48 | 


--------------------------------------------------------------------------------
/include/schema/common/donates.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/donates.json",
 4 |     "description": "Donate plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/",
 5 |     "type": "array",
 6 |     "items": {
 7 |         "type": "object",
 8 |         "oneOf": [
 9 |             {
10 |                 "$ref": "/donate/afdian.json"
11 |             },
12 |             {
13 |                 "$ref": "/donate/alipay.json"
14 |             },
15 |             {
16 |                 "$ref": "/donate/buymeacoffee.json"
17 |             },
18 |             {
19 |                 "$ref": "/donate/patreon.json"
20 |             },
21 |             {
22 |                 "$ref": "/donate/paypal.json"
23 |             },
24 |             {
25 |                 "$ref": "/donate/wechat.json"
26 |             }
27 |         ]
28 |     }
29 | }


--------------------------------------------------------------------------------
/include/schema/common/footer.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/footer.json",
 4 |     "description": "Page footer configurations",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "copyright": {
 8 |             "description": "Copyright text",
 9 |             "type": "string",
10 |             "examples": [
11 |                 "© 2019",
12 |                 "© 2019 - 2020",
13 |                 "© 2019 - 2020, Company Name",
14 |                 "© 2019 - 2020, Company Name. All rights reserved.",
15 |                 "粤ICP备12345678号"
16 |             ]
17 |         },
18 |         "links": {
19 |             "$ref": "/misc/poly_links.json",
20 |             "description": "Links to be shown on the right of the footer section",
21 |             "examples": [
22 |                 {
23 |                     "Creative Commons": {
24 |                         "icon": "fab fa-creative-commons",
25 |                         "url": "https://creativecommons.org/"
26 |                     },
27 |                     "Attribution 4.0 International": {
28 |                         "icon": "fab fa-creative-commons-by",
29 |                         "url": "https://creativecommons.org/licenses/by/4.0/"
30 |                     },
31 |                     "Download on GitHub": {
32 |                         "icon": "fab fa-github",
33 |                         "url": "https://github.com/ppoffice/hexo-theme-icarus"
34 |                     }
35 |                 }
36 |             ]
37 |         }
38 |     }
39 | }


--------------------------------------------------------------------------------
/include/schema/common/head.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/head.json",
 4 |     "description": "Page metadata configurations",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "favicon": {
 8 |             "type": "string",
 9 |             "description": "URL or path to the website's icon",
10 |             "default": "/img/favicon.svg",
11 |             "nullable": true
12 |         },
13 |         "manifest": {
14 |             "$ref": "/misc/manifest.json"
15 |         },
16 |         "open_graph": {
17 |             "$ref": "/misc/open_graph.json"
18 |         },
19 |         "structured_data": {
20 |             "$ref": "/misc/structured_data.json"
21 |         },
22 |         "meta": {
23 |             "$ref": "/misc/meta.json"
24 |         },
25 |         "rss": {
26 |             "type": "string",
27 |             "description": "URL or path to the website's RSS atom.xml",
28 |             "nullable": true
29 |         }
30 |     }
31 | }


--------------------------------------------------------------------------------
/include/schema/common/navbar.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/navbar.json",
 4 |     "description": "Page top navigation bar configurations",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "menu": {
 8 |             "type": "object",
 9 |             "description": "Navigation menu items",
10 |             "patternProperties": {
11 |                 ".+": {
12 |                     "type": "string",
13 |                     "description": "URL or path of the menu link"
14 |                 }
15 |             },
16 |             "examples": [
17 |                 {
18 |                     "Home": "/",
19 |                     "Archives": "/archives",
20 |                     "Categories": "/categories",
21 |                     "Tags": "/tags",
22 |                     "About": "/about"
23 |                 }
24 |             ],
25 |             "nullable": true
26 |         },
27 |         "links": {
28 |             "$ref": "/misc/poly_links.json",
29 |             "description": "Links to be shown on the right of the navigation bar",
30 |             "examples": [
31 |                 {
32 |                     "Download on GitHub": {
33 |                         "icon": "fab fa-github",
34 |                         "url": "https://github.com/ppoffice/hexo-theme-icarus"
35 |                     }
36 |                 }
37 |             ]
38 |         }
39 |     }
40 | }


--------------------------------------------------------------------------------
/include/schema/common/plugins.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/plugins.json",
 4 |     "description": "Plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "animejs": {
 8 |             "$ref": "/plugin/animejs.json"
 9 |         },
10 |         "back_to_top": {
11 |             "$ref": "/plugin/back_to_top.json"
12 |         },
13 |         "baidu_analytics": {
14 |             "$ref": "/plugin/baidu_analytics.json"
15 |         },
16 |         "bing_webmaster": {
17 |             "$ref": "/plugin/bing_webmaster.json"
18 |         },
19 |         "busuanzi": {
20 |             "$ref": "/plugin/busuanzi.json"
21 |         },
22 |         "cnzz": {
23 |             "$ref": "/plugin/cnzz.json"
24 |         },
25 |         "cookie_consent": {
26 |             "$ref": "/plugin/cookie_consent.json"
27 |         },
28 |         "gallery": {
29 |             "$ref": "/plugin/gallery.json"
30 |         },
31 |         "google_analytics": {
32 |             "$ref": "/plugin/google_analytics.json"
33 |         },
34 |         "hotjar": {
35 |             "$ref": "/plugin/hotjar.json"
36 |         },
37 |         "katex": {
38 |             "$ref": "/plugin/katex.json"
39 |         },
40 |         "mathjax": {
41 |             "$ref": "/plugin/mathjax.json"
42 |         },
43 |         "outdated_browser": {
44 |             "$ref": "/plugin/outdated_browser.json"
45 |         },
46 |         "pjax": {
47 |             "$ref": "/plugin/pjax.json"
48 |         },
49 |         "progressbar": {
50 |             "$ref": "/plugin/progressbar.json"
51 |         },
52 |         "statcounter": {
53 |             "$ref": "/plugin/statcounter.json"
54 |         },
55 |         "twitter_conversion_tracking": {
56 |             "$ref": "/plugin/twitter_conversion_tracking.json"
57 |         }
58 |     }
59 | }


--------------------------------------------------------------------------------
/include/schema/common/providers.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/providers.json",
 4 |     "description": "CDN provider settings\nhttps://ppoffice.github.io/hexo-theme-icarus/Configuration/Theme/speed-up-your-site-with-custom-cdn/",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "cdn": {
 8 |             "type": "string",
 9 |             "description": "Name or URL template of the JavaScript and/or stylesheet CDN provider",
10 |             "default": "jsdelivr",
11 |             "nullable": true
12 |         },
13 |         "fontcdn": {
14 |             "type": "string",
15 |             "description": "Name or URL template of the webfont CDN provider",
16 |             "default": "google",
17 |             "nullable": true
18 |         },
19 |         "iconcdn": {
20 |             "type": "string",
21 |             "description": "Name or URL of the fontawesome icon font CDN provider",
22 |             "default": "fontawesome",
23 |             "nullable": true
24 |         }
25 |     }
26 | }


--------------------------------------------------------------------------------
/include/schema/common/search.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/search.json",
 4 |     "description": "Search plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/",
 5 |     "type": "object",
 6 |     "oneOf": [
 7 |         {
 8 |             "$ref": "/search/insight.json"
 9 |         },
10 |         {
11 |             "$ref": "/search/baidu.json"
12 |         },
13 |         {
14 |             "$ref": "/search/google_cse.json"
15 |         },
16 |         {
17 |             "$ref": "/search/algolia.json"
18 |         }
19 |     ]
20 | }


--------------------------------------------------------------------------------
/include/schema/common/share.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/share.json",
 4 |     "description": "Share plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/",
 5 |     "type": "object",
 6 |     "oneOf": [
 7 |         {
 8 |             "$ref": "/share/sharethis.json"
 9 |         },
10 |         {
11 |             "$ref": "/share/addthis.json"
12 |         },
13 |         {
14 |             "$ref": "/share/addtoany.json"
15 |         },
16 |         {
17 |             "$ref": "/share/bdshare.json"
18 |         },
19 |         {
20 |             "$ref": "/share/sharejs.json"
21 |         }
22 |     ]
23 | }


--------------------------------------------------------------------------------
/include/schema/common/sidebar.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/sidebar.json",
 4 |     "description": "Sidebar configurations.\nPlease be noted that a sidebar is only visible when it has at least one widget",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "left": {
 8 |             "type": "object",
 9 |             "description": "Left sidebar configurations",
10 |             "properties": {
11 |                 "sticky": {
12 |                     "type": "boolean",
13 |                     "description": "Whether the sidebar sticks to the top when page scrolls",
14 |                     "default": false
15 |                 }
16 |             }
17 |         },
18 |         "right": {
19 |             "type": "object",
20 |             "description": "Right sidebar configurations",
21 |             "properties": {
22 |                 "sticky": {
23 |                     "type": "boolean",
24 |                     "description": "Whether the sidebar sticks to the top when page scrolls",
25 |                     "default": false
26 |                 }
27 |             }
28 |         }
29 |     }
30 | }


--------------------------------------------------------------------------------
/include/schema/common/widgets.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/common/widgets.json",
 4 |     "description": "Sidebar widget configurations\nhttp://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/",
 5 |     "type": "array",
 6 |     "items": {
 7 |         "type": "object",
 8 |         "properties": {
 9 |             "position": {
10 |                 "type": "string",
11 |                 "description": "Where should the widget be placed, left sidebar or right sidebar",
12 |                 "default": "left"
13 |             }
14 |         },
15 |         "oneOf": [
16 |             {
17 |                 "$ref": "/widget/profile.json"
18 |             },
19 |             {
20 |                 "$ref": "/widget/toc.json"
21 |             },
22 |             {
23 |                 "$ref": "/widget/links.json"
24 |             },
25 |             {
26 |                 "$ref": "/widget/categories.json"
27 |             },
28 |             {
29 |                 "$ref": "/widget/recent_posts.json"
30 |             },
31 |             {
32 |                 "$ref": "/widget/archives.json"
33 |             },
34 |             {
35 |                 "$ref": "/widget/tags.json"
36 |             },
37 |             {
38 |                 "$ref": "/widget/subscribe_email.json"
39 |             },
40 |             {
41 |                 "$ref": "/widget/adsense.json"
42 |             },
43 |             {
44 |                 "$ref": "/widget/followit.json"
45 |             }
46 |         ],
47 |         "required": [
48 |             "position"
49 |         ]
50 |     }
51 | }


--------------------------------------------------------------------------------
/include/schema/config.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/config.json",
 4 |     "description": "The configuration file definition",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "version": {
 8 |             "type": "string",
 9 |             "description": "Version of the configuration file",
10 |             "default": "5.1.0"
11 |         },
12 |         "variant": {
13 |             "type": "string",
14 |             "description": "Icarus theme variant, can be \"default\" or \"cyberpunk\"",
15 |             "enum": [
16 |                 "default",
17 |                 "cyberpunk"
18 |             ],
19 |             "default": "default"
20 |         },
21 |         "logo": {
22 |             "type": [
23 |                 "string",
24 |                 "object"
25 |             ],
26 |             "description": "Path or URL to the website's logo",
27 |             "default": "/img/logo.svg",
28 |             "properties": {
29 |                 "text": {
30 |                     "type": "string",
31 |                     "description": "Text to be shown in place of the logo image"
32 |                 }
33 |             },
34 |             "required": [
35 |                 "text"
36 |             ]
37 |         },
38 |         "head": {
39 |             "$ref": "/common/head.json"
40 |         },
41 |         "navbar": {
42 |             "$ref": "/common/navbar.json"
43 |         },
44 |         "footer": {
45 |             "$ref": "/common/footer.json"
46 |         },
47 |         "article": {
48 |             "$ref": "/common/article.json"
49 |         },
50 |         "search": {
51 |             "$ref": "/common/search.json"
52 |         },
53 |         "comment": {
54 |             "$ref": "/common/comment.json"
55 |         },
56 |         "donates": {
57 |             "$ref": "/common/donates.json"
58 |         },
59 |         "share": {
60 |             "$ref": "/common/share.json"
61 |         },
62 |         "sidebar": {
63 |             "$ref": "/common/sidebar.json"
64 |         },
65 |         "widgets": {
66 |             "$ref": "/common/widgets.json"
67 |         },
68 |         "plugins": {
69 |             "$ref": "/common/plugins.json"
70 |         },
71 |         "providers": {
72 |             "$ref": "/common/providers.json"
73 |         }
74 |     },
75 |     "required": [
76 |         "version"
77 |     ]
78 | }


--------------------------------------------------------------------------------
/include/schema/donate/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/include/schema/donate/.gitkeep


--------------------------------------------------------------------------------
/include/schema/misc/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/include/schema/misc/.gitkeep


--------------------------------------------------------------------------------
/include/schema/plugin/animejs.json:
--------------------------------------------------------------------------------
1 | {
2 |     "$schema": "http://json-schema.org/draft-07/schema#",
3 |     "$id": "/plugin/animejs.json",
4 |     "description": "Enable page startup animations",
5 |     "type": "boolean",
6 |     "default": true
7 | }


--------------------------------------------------------------------------------
/include/schema/plugin/back_to_top.json:
--------------------------------------------------------------------------------
1 | {
2 |     "$schema": "http://json-schema.org/draft-07/schema#",
3 |     "$id": "/plugin/back_to_top.json",
4 |     "description": "Show the \"back to top\" button",
5 |     "type": "boolean",
6 |     "default": true
7 | }


--------------------------------------------------------------------------------
/include/schema/plugin/pjax.json:
--------------------------------------------------------------------------------
1 | {
2 |     "$schema": "http://json-schema.org/draft-07/schema#",
3 |     "$id": "/plugin/pjax.json",
4 |     "description": "Enable PJAX",
5 |     "type": "boolean",
6 |     "default": true
7 | }


--------------------------------------------------------------------------------
/include/schema/search/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/include/schema/search/.gitkeep


--------------------------------------------------------------------------------
/include/schema/share/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/include/schema/share/.gitkeep


--------------------------------------------------------------------------------
/include/schema/widget/profile.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "http://json-schema.org/draft-07/schema#",
 3 |     "$id": "/widget/profile.json",
 4 |     "description": "Profile widget configurations",
 5 |     "type": "object",
 6 |     "properties": {
 7 |         "type": {
 8 |             "type": "string",
 9 |             "const": "profile",
10 |             "nullable": true
11 |         },
12 |         "author": {
13 |             "type": "string",
14 |             "description": "Author name",
15 |             "examples": [
16 |                 "Your name"
17 |             ],
18 |             "nullable": true
19 |         },
20 |         "author_title": {
21 |             "type": "string",
22 |             "description": "Author title",
23 |             "examples": [
24 |                 "Your title"
25 |             ],
26 |             "nullable": true
27 |         },
28 |         "location": {
29 |             "type": "string",
30 |             "description": "Author's current location",
31 |             "examples": [
32 |                 "Your location"
33 |             ],
34 |             "nullable": true
35 |         },
36 |         "avatar": {
37 |             "type": "string",
38 |             "description": "URL or path to the avatar image",
39 |             "nullable": true
40 |         },
41 |         "avatar_rounded": {
42 |             "type": "boolean",
43 |             "description": "Whether show the rounded avatar image",
44 |             "default": false,
45 |             "nullable": true
46 |         },
47 |         "gravatar": {
48 |             "type": "string",
49 |             "description": "Email address for the Gravatar",
50 |             "nullable": true
51 |         },
52 |         "follow_link": {
53 |             "type": "string",
54 |             "description": "URL or path for the follow button",
55 |             "examples": [
56 |                 "https://github.com/ppoffice"
57 |             ],
58 |             "nullable": true
59 |         },
60 |         "social_links": {
61 |             "$ref": "/misc/poly_links.json",
62 |             "description": "Links to be shown on the bottom of the profile widget",
63 |             "examples": [
64 |                 {
65 |                     "Github": {
66 |                         "icon": "fab fa-github",
67 |                         "url": "https://github.com/ppoffice"
68 |                     },
69 |                     "Facebook": {
70 |                         "icon": "fab fa-facebook",
71 |                         "url": "https://facebook.com"
72 |                     },
73 |                     "Twitter": {
74 |                         "icon": "fab fa-twitter",
75 |                         "url": "https://twitter.com"
76 |                     },
77 |                     "Dribbble": {
78 |                         "icon": "fab fa-dribbble",
79 |                         "url": "https://dribbble.com"
80 |                     },
81 |                     "RSS": {
82 |                         "icon": "fas fa-rss",
83 |                         "url": "/"
84 |                     }
85 |                 }
86 |             ]
87 |         }
88 |     },
89 |     "required": [
90 |         "type"
91 |     ]
92 | }


--------------------------------------------------------------------------------
/include/style/article.styl:
--------------------------------------------------------------------------------
  1 | /* ---------------------------------
  2 |  *    Article Summary and Content
  3 |  * --------------------------------- */
  4 | $article-font-size ?= 1.1rem
  5 | 
  6 | article
  7 |     &.media
  8 |         color: $text-light
  9 | 
 10 |         a
 11 |             color: inherit
 12 | 
 13 |             &:hover
 14 |                 color: $primary
 15 | 
 16 |         .image
 17 |             width: 64px
 18 |             height: 64px
 19 | 
 20 |             img
 21 |                 object-fit: cover
 22 |                 width: 100%
 23 |                 height: 100%
 24 | 
 25 |         .title
 26 |             @extend .is-size-6
 27 |             margin-bottom: .25em
 28 | 
 29 |         .date, .categories
 30 |             @extend .is-size-7
 31 | 
 32 |         .categories
 33 |             @extend .is-uppercase
 34 | 
 35 |         .media-content
 36 |             color: $text-light
 37 | 
 38 |             .title
 39 |                 margin: 0
 40 |                 line-height: inherit
 41 | 
 42 |     &.article
 43 |         .article-meta, .article-tags
 44 |             color: $text-light
 45 | 
 46 |         .article-meta
 47 |             overflow-x: auto
 48 |             margin-bottom: .5rem
 49 | 
 50 |         .article-more
 51 |             @extend .button.is-light
 52 | 
 53 |         .content
 54 |             word-wrap: break-word
 55 |             font-size: $article-font-size
 56 | 
 57 |             h1
 58 |                 font-size: 1.75em
 59 | 
 60 |             h2
 61 |                 font-size: 1.5em
 62 | 
 63 |             h3
 64 |                 font-size: 1.25em
 65 | 
 66 |             h4
 67 |                 font-size: 1.125em
 68 | 
 69 |             h5
 70 |                 font-size: 1em
 71 | 
 72 |             pre
 73 |                 font-size: .85em
 74 | 
 75 |             code
 76 |                 padding: 0
 77 |                 background: transparent
 78 |                 overflow-wrap: break-word
 79 | 
 80 |             blockquote
 81 |                 &.pullquote
 82 |                     float: right
 83 |                     max-width: 50%
 84 |                     font-size: 1.15rem
 85 |                     position: relative
 86 | 
 87 |                 footer
 88 |                     strong + cite
 89 |                         margin-left: .5em
 90 | 
 91 |             .message.message-immersive
 92 |                 border-radius: 0
 93 |                 margin: 0 0 - $card-content-padding $card-content-padding 0 - $card-content-padding
 94 | 
 95 |                 .message-body
 96 |                     border: none
 97 |         
 98 |         .article-tags
 99 |             display: flex
100 |             flex-wrap: wrap
101 | 
102 | .rtl
103 |     direction: rtl
104 | 
105 |     .level
106 |         &, &.is-mobile
107 |             .level-item:not(:last-child)
108 |                 margin-left: .75rem
109 |                 margin-right: 0
110 | 
111 | // Overflow table
112 | .table-overflow
113 |     overflow-x: auto
114 | 
115 |     table
116 |         width: auto !important
117 | 
118 |         th
119 |             word-break: keep-all
120 | 
121 | // Video container
122 | .video-container
123 |     position: relative
124 |     padding-bottom: 56.25%
125 |     padding-top: 25px
126 |     height: 0
127 | 
128 |     iframe
129 |         position: absolute
130 |         top: 0
131 |         left: 0
132 |         width: 100%
133 |         height: 100%
134 | 
135 | .article-licensing
136 |     position: relative
137 |     z-index: 1
138 |     box-shadow: none
139 |     background: $white-ter
140 |     border-radius: $radius
141 |     overflow: hidden
142 | 
143 |     &:after
144 |         position: absolute
145 |         z-index: -1
146 |         right: -50px
147 |         top: -87.87px
148 |         content: '\f25e'
149 |         font-size: 200px
150 |         font-family: 'Font Awesome 5 Brands'
151 |         opacity: .1
152 | 
153 |     .level-left
154 |         flex-wrap: wrap
155 |         max-width: 100%
156 | 
157 |     .licensing-title
158 |         @extend .mb-3
159 |         line-height: 1.2
160 | 
161 |         p:not(:last-child)
162 |             @extend .mb-1
163 | 
164 |         a
165 |             @extend .is-size-7, .has-text-grey
166 | 
167 |     .licensing-meta
168 |         .level-item
169 |             @extend .mr-4
170 | 
171 |         .icons
172 |             .icon
173 |                 @extend .ml-1
174 |                 width: 1.2em
175 |                 height: 1.2em
176 |                 font-size: 1.2em
177 |                 vertical-align: bottom
178 | 
179 |         h6
180 |             @extend .is-size-7
181 | 
182 |         a
183 |             color: inherit
184 | 
185 | a
186 |     &.article-nav-prev
187 |         span
188 |             text-align: left
189 |             flex-shrink: 1
190 |             word-wrap: break-word
191 |             white-space: normal
192 | 
193 |     &.article-nav-next
194 |         span
195 |             text-align: right
196 |             flex-shrink: 1
197 |             word-wrap: break-word
198 |             white-space: normal


--------------------------------------------------------------------------------
/include/style/base.styl:
--------------------------------------------------------------------------------
  1 | bulma-stylus-root = '../../../../node_modules/bulma-stylus/stylus'
  2 | 
  3 | /* ---------------------------------
  4 |  *   Override Bulma CSS Framework
  5 |  * --------------------------------- */
  6 | $body-size ?= 14px
  7 | $body-background-color ?= #f7f7f7
  8 | 
  9 | $family-sans-serif ?= Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif
 10 | $family-code ?= 'Source Code Pro', monospace, 'Microsoft YaHei'
 11 | 
 12 | $size-7 ?= .85rem
 13 | $size-small ?= .75rem
 14 | 
 15 | $primary ?= $blue
 16 | $custom-colors ?= {
 17 |     grey-lightest: {
 18 |         '1': $grey-lightest
 19 |         '2': $grey-darker
 20 |     }
 21 | }
 22 | 
 23 | $navbar-item-active-color ?= $primary
 24 | $footer-background-color ?= $scheme-main
 25 | 
 26 | $gap ?= 64px
 27 | $tablet ?= 769px
 28 | $desktop ?= 1088px
 29 | $widescreen ?= 1280px
 30 | $fullhd ?= 1472px
 31 | 
 32 | $shadow ?= 0 4px 10px rgba(0, 0, 0, 0.05)
 33 | 
 34 | $title-weight ?= $weight-normal
 35 | 
 36 | $control-height ?= 2.25em
 37 | $button-padding-vertical ?= calc(0.375em - 1px)
 38 | 
 39 | $card-radius ?= $radius
 40 | $card-media-margin ?= 0.75rem
 41 | $card-shadow ?= $shadow, 0 0 1px rgba(0, 0, 0, 0.1)
 42 | 
 43 | $menu-item-active-color ?= $link
 44 | $menu-item-active-background-color ?= hsl(219, 70%, 96%)
 45 | 
 46 | $content-heading-weight ?= $weight-normal
 47 | 
 48 | 
 49 | $logo-height ?= 1.75rem
 50 | 
 51 | // FIXME: https://github.com/groenroos/bulma-stylus/issues/11
 52 | @import bulma-stylus-root + '/utilities/initial-variables'
 53 | @import bulma-stylus-root + '/utilities/functions'
 54 | @import bulma-stylus-root + '/utilities/derived-variables'
 55 | 
 56 | $colors = merge($colors, $custom-colors)
 57 | 
 58 | @import bulma-stylus-root + '/utilities/animations'
 59 | @import bulma-stylus-root + '/utilities/mixins'
 60 | @import bulma-stylus-root + '/utilities/controls'
 61 | @import bulma-stylus-root + '/base/_all'
 62 | @import bulma-stylus-root + '/components/_all'
 63 | @import bulma-stylus-root + '/elements/_all'
 64 | @import bulma-stylus-root + '/form/_all'
 65 | @import bulma-stylus-root + '/grid/_all'
 66 | @import bulma-stylus-root + '/layout/_all'
 67 | 
 68 | html
 69 |     height: 100%
 70 |     -webkit-text-size-adjust: 100%
 71 |     -moz-text-size-adjust: 100%
 72 |     -ms-text-size-adjust: 100%
 73 |     text-size-adjust: 100%
 74 | 
 75 | body
 76 |     min-height: 100%
 77 |     display: flex
 78 |     flex-direction: column
 79 | 
 80 | body > .section
 81 |     flex-grow: 1
 82 | 
 83 | +desktop()
 84 |     ::-webkit-scrollbar
 85 |         width: 8px
 86 |         height: 8px
 87 | 
 88 |     ::-webkit-scrollbar-track
 89 |         border-radius: 3px
 90 |         background: rgba(0,0,0,0.06)
 91 |         box-shadow: inset 0 0 5px rgba(0,0,0,0.1)
 92 | 
 93 |     ::-webkit-scrollbar-thumb
 94 |         border-radius: 3px
 95 |         background: rgba(0,0,0,0.12)
 96 |         box-shadow: inset 0 0 10px rgba(0,0,0,0.2)
 97 | 
 98 |     ::-webkit-scrollbar-thumb:hover
 99 |         background: rgba(0,0,0,0.24)
100 | 


--------------------------------------------------------------------------------
/include/style/button.styl:
--------------------------------------------------------------------------------
1 | /* ---------------------------------
2 |  *            Buttons
3 |  * --------------------------------- */
4 | .button
5 |     &.is-transparent
6 |         color: inherit
7 |         background: transparent
8 |         border-color: transparent
9 | 


--------------------------------------------------------------------------------
/include/style/card.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *              Card
 3 |  * --------------------------------- */
 4 | .card
 5 |     overflow: visible
 6 |     border-radius: $card-radius
 7 | 
 8 |     & + .card, & + .column-right-shadow
 9 |         margin-top: 1.5rem
10 | 
11 |     .card-image
12 |         overflow: hidden
13 |         border-top-left-radius: $card-radius
14 |         border-top-right-radius: $card-radius
15 | 
16 |     .media + .media
17 |         border: none
18 |         margin-top: 0
19 | 


--------------------------------------------------------------------------------
/include/style/codeblock.styl:
--------------------------------------------------------------------------------
  1 | /* ---------------------------------
  2 |  *          Code Highlight
  3 |  * --------------------------------- */
  4 | $codeblock-caption-bg ?= rgba(200, 200, 200, .15)
  5 | 
  6 | figure.highlight
  7 |     padding: 0
  8 |     width: 100%
  9 |     position: relative
 10 |     margin: 1em 0 1em !important
 11 |     border-radius: $radius
 12 | 
 13 |     &.folded
 14 |         .highlight-body
 15 |             height: 0
 16 | 
 17 |     .copy
 18 |         opacity: .7
 19 | 
 20 |     pre, table tr:hover
 21 |         color: inherit
 22 |         background: transparent
 23 | 
 24 |     table
 25 |         width: auto
 26 | 
 27 |         tr td
 28 |             border: none
 29 | 
 30 |         tr:not(:first-child) td
 31 |             padding-top: 0
 32 | 
 33 |         tr:not(:last-child) td
 34 |             padding-bottom: 0
 35 | 
 36 |     pre
 37 |         padding: 0
 38 |         overflow: visible
 39 | 
 40 |         .line, code .hljs
 41 |             line-height: 1.5rem
 42 | 
 43 |     figcaption, .gutter
 44 |         background: $codeblock-caption-bg
 45 | 
 46 |     figcaption
 47 |         margin: 0 !important
 48 |         padding: .3em 0em .3em .75em
 49 |         font-style: normal
 50 |         font-size: .8em
 51 | 
 52 |         *
 53 |             color: inherit
 54 | 
 55 |         span
 56 |             font-weight: 500
 57 |             font-family: $family-code
 58 | 
 59 |         .level-left *:not(:last-child)
 60 |             margin-right: .5em
 61 | 
 62 |         .level-right *:not(:first-child)
 63 |             margin-left: .5em
 64 | 
 65 |         .fold
 66 |             cursor: pointer
 67 | 
 68 |         &.level
 69 |             overflow: auto
 70 | 
 71 |             .level-right
 72 |                 a
 73 |                     padding: 0em .75em
 74 | 
 75 |     .highlight-body
 76 |         overflow: auto
 77 | 
 78 |     .gutter
 79 |         text-align: right
 80 | 
 81 |     .tag, .title, .number, .section
 82 |         display: inherit
 83 |         font: inherit
 84 |         margin: inherit
 85 |         padding: inherit
 86 |         background: inherit
 87 |         height: inherit
 88 |         text-align: inherit
 89 |         vertical-align: inherit
 90 |         min-width: inherit
 91 |         border-radius: inherit
 92 | 
 93 | figure.highlight.foldable
 94 |   div.level-left
 95 |     cursor: pointer  // clicking the codeblock filename can toggle folding 
 96 | 
 97 | /* ---------------------------------
 98 |  *        Fix Gist Snippet
 99 |  * --------------------------------- */
100 | .gist
101 |     table
102 |         tr:hover
103 |             background: transparent
104 | 
105 |         td
106 |             border: none
107 | 
108 |     .file
109 |         all: initial
110 | 


--------------------------------------------------------------------------------
/include/style/donate.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *          Donate Buttons
 3 |  * --------------------------------- */
 4 | $donate-qrcode-max-width ?= 280px
 5 | $donate-qrcode-shadow ?= $card-shadow
 6 | $donate-qrcode-box-radius ?= $card-radius
 7 | 
 8 | $donate-button-colors ?= {
 9 |     'afdian': rgb(136, 95, 217),
10 |     'alipay': rgb(0, 160, 232),
11 |     'buymeacoffee': rgb(255, 221, 0),
12 |     'paypal': rgb(254, 183, 0),
13 |     'patreon': rgb(255, 66, 77),
14 |     'wechat': rgb(26, 173, 25),
15 | }
16 | 
17 | .donate
18 |     position: relative
19 | 
20 |     .qrcode
21 |         display: none
22 |         position: absolute
23 |         z-index: 99
24 |         bottom: 2.5em
25 |         line-height: 0
26 |         overflow: hidden
27 |         box-shadow: $donate-qrcode-shadow
28 |         border-radius: $donate-qrcode-box-radius
29 | 
30 |         img
31 |             max-width: $donate-qrcode-max-width
32 | 
33 |     &:hover
34 |         .qrcode
35 |             display: block
36 | 
37 |     &:first-child:not(:last-child)
38 |         .qrcode
39 |             left: -.75rem
40 | 
41 |     &:last-child:not(:first-child)
42 |         .qrcode
43 |             right: -.75rem
44 | 
45 |     for $name, $color in $donate-button-colors
46 |         &[data-type={'"' + $name + '"'}]
47 |             color: findColorInvert($color)
48 |             background-color: $color
49 |             border-color: transparent
50 | 
51 |             &:active
52 |                 background-color: darken($color, 5%)
53 | 
54 |             &:hover
55 |                 background-color: darken($color, 2.5%)
56 | 
57 |             &:focus:not(:active)
58 |                 box-shadow: 0 0 0 .125em rgba($color, .25)
59 | 


--------------------------------------------------------------------------------
/include/style/footer.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *            Page Footer
 3 |  * --------------------------------- */
 4 | footer.footer
 5 |     .level-start
 6 |         +mobile()
 7 |             text-align: center
 8 | 
 9 |     .level-end
10 |         .field
11 |             flex-wrap: wrap
12 |             align-items: center
13 | 
14 |             +mobile()
15 |                 justify-content: center
16 |                 margin-top: 1rem
17 | 
18 | .footer-logo
19 |     img
20 |         max-height: $logo-height
21 | 


--------------------------------------------------------------------------------
/include/style/helper.styl:
--------------------------------------------------------------------------------
  1 | /* ---------------------------------
  2 |  *          Spacing helpers
  3 |  * --------------------------------- */
  4 | $spacer ?= 1rem
  5 | $spacers ?= 0, $spacer * .25, $spacer * .5, $spacer, $spacer * 1.5, $spacer * 3
  6 | 
  7 | for n in (0 .. 5)
  8 |     .ml-{n}
  9 |         margin-left: $spacers[n] !important
 10 | 
 11 |     .mr-{n}
 12 |         margin-right: $spacers[n] !important
 13 | 
 14 |     .mx-{n}
 15 |         @extend .ml-{n}, .mr-{n}
 16 | 
 17 |     .ml-n{n}
 18 |         margin-left: - $spacers[n] !important
 19 | 
 20 |     .mr-n{n}
 21 |         margin-right: - $spacers[n] !important
 22 | 
 23 |     .mx-n{n}
 24 |         @extend .ml-n{n}, .mr-n{n}
 25 | 
 26 |     .mt-{n}
 27 |         margin-top: $spacers[n] !important
 28 | 
 29 |     .mb-{n}
 30 |         margin-bottom: $spacers[n] !important
 31 | 
 32 |     .my-{n}
 33 |         @extend .mt-{n}, .mb-{n}
 34 | 
 35 |     .mt-n{n}
 36 |         margin-top: - $spacers[n] !important
 37 | 
 38 |     .mb-n{n}
 39 |         margin-bottom: - $spacers[n] !important
 40 | 
 41 |     .my-n{n}
 42 |         @extend .mt-n{n}, .mb-n{n}
 43 | 
 44 |     .pl-{n}
 45 |         padding-left: $spacers[n] !important
 46 | 
 47 |     .pr-{n}
 48 |         padding-right: $spacers[n] !important
 49 | 
 50 |     .px-{n}
 51 |         @extend .pl-{n}, .pr-{n}
 52 | 
 53 |     .pl-n{n}
 54 |         padding-left: - $spacers[n] !important
 55 | 
 56 |     .pr-n{n}
 57 |         padding-right: - $spacers[n] !important
 58 | 
 59 |     .px-n{n}
 60 |         @extend .pl-n{n}, .pr-n{n}
 61 | 
 62 |     .pt-{n}
 63 |         padding-top: $spacers[n] !important
 64 | 
 65 |     .pb-{n}
 66 |         padding-bottom: $spacers[n] !important
 67 | 
 68 |     .py-{n}
 69 |         @extend .pt-{n}, .pb-{n}
 70 | 
 71 |     .pt-n{n}
 72 |         padding-top: - $spacers[n] !important
 73 | 
 74 |     .pb-n{n}
 75 |         padding-bottom: - $spacers[n] !important
 76 | 
 77 |     .py-n{n}
 78 |         @extend .pt-n{n}, .pb-n{n}
 79 | 
 80 | .ml-auto
 81 |     margin-left: auto !important
 82 | 
 83 | .mr-auto
 84 |     margin-right: auto !important
 85 | 
 86 | .mx-auto
 87 |     @extend .ml-auto, .mr-auto
 88 | 
 89 | .mt-auto
 90 |     margin-top: auto !important
 91 | 
 92 | .mb-auto
 93 |     margin-bottom: auto !important
 94 | 
 95 | .my-auto
 96 |     @extend .mt-auto, .mb-auto
 97 | 
 98 | .pl-auto
 99 |     margin-left: auto !important
100 | 
101 | .pr-auto
102 |     margin-right: auto !important
103 | 
104 | .px-auto
105 |     @extend .pl-auto, .pr-auto
106 | 
107 | .pt-auto
108 |     margin-top: auto !important
109 | 
110 | .pb-auto
111 |     margin-bottom: auto !important
112 | 
113 | .py-auto
114 |     @extend .pt-auto, .pb-auto
115 | 
116 | /* ---------------------------------
117 |  *           Flex helpers
118 |  * --------------------------------- */
119 | for n in (0 .. 5)
120 |     .order-{n}
121 |         order: n !important
122 | 
123 | .justify-content-start
124 |     justify-content: start !important
125 | 
126 | .justify-content-center
127 |     justify-content: center !important
128 | 
129 | .flex-shrink-1
130 |     flex-shrink: 1 !important
131 | 
132 | /* ---------------------------------
133 |  *           Color helpers
134 |  * --------------------------------- */
135 | .link-muted
136 |     color: inherit
137 | 
138 |     &:hover
139 |         color: $primary !important
140 | 
141 | /* ---------------------------------
142 |  *          Image helpers
143 |  * --------------------------------- */
144 | .image
145 |     &.is-7by3
146 |         padding-top: 42.8%
147 | 
148 |         img
149 |             bottom: 0
150 |             left: 0
151 |             position: absolute
152 |             right: 0
153 |             top: 0
154 | 
155 |     .avatar
156 |         height: 100%
157 |         object-fit: cover
158 | 
159 |     .fill
160 |         object-fit: cover
161 |         width: 100% !important
162 |         height: 100% !important


--------------------------------------------------------------------------------
/include/style/navbar.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *           Top Navigation
 3 |  * --------------------------------- */
 4 | $navbar-item-padding-v ?= 1.25rem
 5 | $navbar-item-padding-h ?= .75rem
 6 | $navbar-item-margin-v ?= 0
 7 | $navbar-item-margin-h ?= 0
 8 | 
 9 | .navbar-main
10 |     box-shadow: $shadow
11 | 
12 |     .navbar-container
13 |         overflow-x: auto
14 | 
15 |     .navbar-menu, .navbar-start, .navbar-end
16 |         align-items: stretch
17 |         display: flex
18 |         padding: 0
19 |         flex-shrink: 0
20 | 
21 |     .navbar-menu
22 |         flex-grow: 1
23 |         flex-shrink: 0
24 |         overflow-x: auto
25 | 
26 |     .navbar-start
27 |         justify-content: flex-start
28 |         margin-right: auto
29 | 
30 |     .navbar-end
31 |         justify-content: flex-end
32 |         margin-left: auto
33 | 
34 |     .navbar-item
35 |         display: flex
36 |         align-items: center
37 |         padding: $navbar-item-padding-v $navbar-item-padding-h
38 |         margin: $navbar-item-margin-v $navbar-item-margin-h
39 | 
40 |         &.is-active
41 |             background-color: transparent
42 | 
43 |     +until($navbar-breakpoint)
44 |         .navbar-menu
45 |             justify-content: center
46 |             box-shadow: none
47 | 
48 |         .navbar-start
49 |             margin-right: 0
50 | 
51 |         .navbar-end
52 |             margin-left: 0
53 | 
54 | .navbar-logo
55 |     img
56 |         max-height: $logo-height
57 | 
58 | @media screen and (min-width: $desktop)
59 |     .navbar > .container .navbar-menu, .container > .navbar .navbar-menu
60 |         margin-right: 0rem
61 | 


--------------------------------------------------------------------------------
/include/style/pagination.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *  Pagination and Post Navigation
 3 |  * --------------------------------- */
 4 | $pagination-box-shadow ?= $card-shadow
 5 | $pagination-background-color ?= $button-background-color
 6 | $post-navigation-fg ?= $grey
 7 | 
 8 | .pagination
 9 |     @extend .pagination.is-centered
10 |     margin-top: 1.5rem
11 | 
12 |     .pagination-link,
13 |     .pagination-ellipsis,
14 |     .pagination-previous,
15 |     .pagination-next
16 |         a
17 |             color: $pagination-color
18 |     .pagination-link,
19 |     .pagination-previous,
20 |     .pagination-next
21 |         border: none
22 |         background: $pagination-background-color
23 |         box-shadow: $pagination-box-shadow
24 |     .pagination-link.is-current
25 |         background: $pagination-current-background-color
26 | 
27 | .post-navigation
28 |     color: $post-navigation-fg
29 |     flex-wrap: wrap
30 |     justify-content: space-around
31 |     .level-item
32 |         margin-bottom: 0
33 | 


--------------------------------------------------------------------------------
/include/style/plugin.styl:
--------------------------------------------------------------------------------
  1 | /* ---------------------------------
  2 |  *        Back to Top Button
  3 |  * --------------------------------- */
  4 | #back-to-top
  5 |     position: fixed
  6 |     opacity: 0
  7 |     outline: none
  8 |     padding: 8px 0
  9 |     line-height: 24px
 10 |     border-radius: $card-radius
 11 |     transform: translateY(120px)
 12 |     transition: .4s ease opacity, .4s ease width, .4s ease transform, .4s ease border-radius
 13 | 
 14 |     &.is-rounded
 15 |         border-radius: 50%
 16 | 
 17 |     &.fade-in
 18 |         opacity: 1
 19 | 
 20 |     &.rise-up
 21 |         transform: translateY(0)
 22 | 
 23 | /* ---------------------------------
 24 |  *          Gallery Plugin
 25 |  * --------------------------------- */
 26 | .gallery-item
 27 |     .caption
 28 |         color: $grey
 29 | 
 30 | /* ---------------------------------
 31 |  *      Page Loading Progressbar
 32 |  * --------------------------------- */
 33 | .pace
 34 |     user-select: none
 35 |     pointer-events: none
 36 | 
 37 |     .pace-progress
 38 |         top: 0
 39 |         right: 100%
 40 |         width: 100%
 41 |         height: 2px
 42 |         z-index: 2000
 43 |         position: fixed
 44 |         background: $primary
 45 | 
 46 | .pace-inactive
 47 |     display: none
 48 | 
 49 | /* ---------------------------------
 50 |  *       Fix FontAwesome Icons
 51 |  * --------------------------------- */
 52 | .fa, .fab, .fal, .far, .fas
 53 |     line-height: inherit
 54 | 
 55 | /* ---------------------------------
 56 |  *       MathJax and KaTeX
 57 |  * --------------------------------- */
 58 | .MathJax, .MathJax_Display, .MJXc-display, .MathJax_SVG_Display, .katex-display
 59 |     overflow-x: auto
 60 |     overflow-y: hidden
 61 | 
 62 | .katex
 63 |     white-space: nowrap
 64 | 
 65 | .katex-display
 66 |     margin-top: -1em !important
 67 | 
 68 | .katex-html
 69 |     padding-top: 1em
 70 | 
 71 |     .tag
 72 |         align-items: unset
 73 |         background-color: unset
 74 |         border-radius: unset
 75 |         color: unset
 76 |         display: unset
 77 |         font-size: unset
 78 |         height: unset
 79 |         justify-content: unset
 80 |         line-height: unset
 81 |         padding-left: unset
 82 |         padding-right: unset
 83 |         white-space: unset
 84 | 
 85 | /* ---------------------------------
 86 |  *         Cookie Consent
 87 |  * --------------------------------- */
 88 | .cc-window, .cc-revoke
 89 |     font-size: 1.1rem !important
 90 |     font-family: $family-sans-serif !important
 91 | 
 92 | .cc-window
 93 |     color: $text !important
 94 |     background-color: $scheme-main !important
 95 | 
 96 |     &.cc-floating
 97 |         border-radius: $card-radius
 98 |         box-shadow: $card-shadow
 99 | 
100 |     &.cc-banner
101 |         background-color: darken($scheme-main, 2.5%) !important
102 | 
103 |     &.cc-theme-block, &.cc-theme-classic
104 |         .cc-compliance > .cc-btn
105 |             border-radius: $radius-rounded
106 | 
107 |     .cc-compliance > .cc-btn
108 |         font-weight: 400
109 |         border: none
110 |         color: $primary-invert
111 |         background-color: $primary
112 | 
113 |         &:hover, &:focus
114 |             background-color: darken($primary, 2.5%)
115 | 
116 |         &.cc-deny
117 |             &:hover
118 |                 color: $primary
119 |                 text-decoration: none
120 | 
121 | .cc-revoke
122 |     padding: .5rem 1rem !important
123 |     color: $primary-invert !important
124 |     background-color: $primary !important
125 | 
126 |     &:hover
127 |         text-decoration: none !important
128 |         background-color: darken($primary, 2.5%)
129 | 


--------------------------------------------------------------------------------
/include/style/responsive.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *         Responsive Layout
 3 |  * --------------------------------- */
 4 | +widescreen()
 5 |     .is-1-column .container, .is-2-column .container
 6 |         max-width: $desktop - 2 * $gap
 7 |         width: $desktop - 2 * $gap
 8 | 
 9 | +fullhd()
10 |     .is-2-column .container
11 |         max-width: $widescreen - 2 * $gap
12 |         width: $widescreen - 2 * $gap
13 | 
14 |     .is-1-column .container
15 |         max-width: $desktop - 2 * $gap
16 |         width: $desktop - 2 * $gap
17 | 
18 | +tablet()
19 |     .is-sticky
20 |         position: -webkit-sticky
21 |         position: sticky
22 |         top: 1.5rem
23 |         z-index: 99
24 | 
25 |     .column-main, .column-left, .column-right, .column-right-shadow
26 |         &.is-sticky
27 |             top: .75rem
28 |             align-self: flex-start
29 | 
30 | +mobile()
31 |     .section
32 |         padding: 1.5rem 1rem
33 | 


--------------------------------------------------------------------------------
/include/style/search.styl:
--------------------------------------------------------------------------------
  1 | /* ---------------------------------
  2 |  *           Search Box
  3 |  * --------------------------------- */
  4 | // container sizes
  5 | $searchbox-container-width ?= 540px
  6 | $searchbox-container-margin ?= 100px
  7 | $searchbox-breakpoint-width ?= 559px
  8 | $searchbox-breakpoint-height ?= 479px
  9 | // overlay and container styles
 10 | $searchbox-box-shadow ?= $card-shadow
 11 | $searchbox-border-radius ?= $radius
 12 | $searchbox-bg-overlay ?= $modal-background-background-color
 13 | $searchbox-bg-container ?= $white-ter
 14 | $searchbox-border ?= $border
 15 | // header styles
 16 | $searchbox-bg-input ?= $white
 17 | $searchbox-bg-close-hover ?= $searchbox-bg-container
 18 | $searchbox-bg-close-active ?= $grey-lighter
 19 | // body styles
 20 | $searchbox-fg-result-header ?= $grey-light
 21 | $searchbox-fg-result-item-secondary ?= $grey-light
 22 | $searchbox-bg-result-item-hover ?= $searchbox-bg-input
 23 | $searchbox-fg-result-item-active ?= findColorInvert($primary)
 24 | $searchbox-bg-result-item-active ?= $primary
 25 | $searchbox-bg-result-item-highlight ?= $yellow
 26 | // footer styles
 27 | $searchbox-bg-pagination-item ?= $searchbox-bg-input
 28 | $searchbox-bg-pagination-item-hover ?= $searchbox-bg-container
 29 | $searchbox-fg-pagination-item-active ?= findColorInvert($primary)
 30 | $searchbox-bg-pagination-item-active ?= $primary
 31 | $searchbox-bg-pagination-item-disabled ?= $searchbox-bg-container
 32 | 
 33 | .searchbox
 34 |     display: none
 35 |     top: 0
 36 |     left: 0
 37 |     width: 100%
 38 |     height: 100%
 39 |     z-index: 100
 40 |     font-size: 1rem
 41 |     line-height: 0
 42 |     background: $searchbox-bg-overlay
 43 | 
 44 |     &.show
 45 |         display: flex
 46 | 
 47 |     a, a:hover
 48 |         color: inherit
 49 |         text-decoration: none
 50 | 
 51 |     input
 52 |         font-size: 1rem
 53 |         border: none
 54 |         outline: none
 55 |         box-shadow: none
 56 |         border-radius: 0
 57 | 
 58 |     &, .searchbox-container
 59 |         position: fixed
 60 |         align-items: center
 61 |         flex-direction: column
 62 |         line-height: 1.25em
 63 | 
 64 |     .searchbox-container
 65 |         z-index: 101
 66 |         display: flex
 67 |         overflow: hidden
 68 |         box-shadow: $searchbox-box-shadow
 69 |         border-radius: $searchbox-border-radius
 70 |         background-color: $searchbox-bg-container
 71 |         width: $searchbox-container-width
 72 |         top: $searchbox-container-margin
 73 |         bottom: $searchbox-container-margin
 74 | 
 75 |     .searchbox-header, .searchbox-body, .searchbox-footer
 76 |         width: 100%
 77 | 
 78 |     .searchbox-header
 79 |         display: flex
 80 |         flex-direction: row
 81 |         line-height: 1.5em
 82 |         font-weight: normal
 83 |         background-color: $searchbox-bg-input
 84 |         // fix Chrome 71 height issue
 85 |         // https://github.com/ppoffice/hexo-theme-icarus/issues/719
 86 |         min-height: 3rem
 87 | 
 88 |     .searchbox-input-container
 89 |         display: flex
 90 |         flex-grow: 1
 91 | 
 92 |     .searchbox-input
 93 |         flex-grow: 1
 94 |         color: inherit
 95 |         box-sizing: border-box
 96 |         padding: .75em 0 .75em 1.25em
 97 |         background: $searchbox-bg-input
 98 | 
 99 |     .searchbox-close
100 |         display: inline-block
101 |         font-size: 1.5em
102 |         padding: .5em .75em
103 |         cursor: pointer
104 | 
105 |         &:hover
106 |             background: $searchbox-bg-close-hover
107 | 
108 |         &:active
109 |             background: $searchbox-bg-close-active
110 | 
111 |     .searchbox-body
112 |         flex-grow: 1
113 |         overflow-y: auto
114 |         border-top: 1px solid $searchbox-border
115 | 
116 |     .searchbox-result-section header, .searchbox-result-item
117 |         padding: .75em 1em
118 | 
119 |     .searchbox-result-section
120 |         border-bottom: 1px solid $searchbox-border
121 | 
122 |         header
123 |             color: $searchbox-fg-result-header
124 | 
125 |     .searchbox-result-item
126 |         display: flex
127 |         flex-direction: row
128 | 
129 |         &:not(.disabled):not(.active):not(:active):hover
130 |             background-color: $searchbox-bg-result-item-hover
131 | 
132 |         &:active, &.active
133 |             color: $searchbox-fg-result-item-active
134 |             background-color: $searchbox-bg-result-item-active
135 | 
136 |         em
137 |             font-style: normal
138 |             background: $searchbox-bg-result-item-highlight
139 | 
140 |     .searchbox-result-icon
141 |         margin-right: 1em
142 | 
143 |     .searchbox-result-content
144 |         overflow: hidden
145 | 
146 |     .searchbox-result-title, .searchbox-result-preview
147 |         display: block
148 |         overflow: hidden
149 |         white-space: nowrap
150 |         text-overflow: ellipsis
151 | 
152 |     .searchbox-result-title-secondary
153 |         color: $searchbox-fg-result-item-secondary
154 | 
155 |     .searchbox-result-preview
156 |         margin-top: .25em
157 | 
158 |     .searchbox-result-item:not(:active):not(.active)
159 |         .searchbox-result-preview
160 |             color: $searchbox-fg-result-item-secondary
161 | 
162 |     .searchbox-footer
163 |         padding: .5em 1em
164 | 
165 |     .searchbox-pagination
166 |         margin: 0
167 |         padding: 0
168 |         list-style: none
169 |         text-align: center
170 | 
171 |         .searchbox-pagination-item
172 |             margin: 0 .25rem
173 | 
174 |         .searchbox-pagination-item, .searchbox-pagination-link
175 |             display: inline-block
176 | 
177 |         .searchbox-pagination-link
178 |             overflow: hidden
179 |             padding: .5em .8em
180 |             box-shadow: $searchbox-box-shadow
181 |             border-radius: $searchbox-border-radius
182 |             background-color: $searchbox-bg-pagination-item
183 | 
184 |         .searchbox-pagination-item.active
185 |             .searchbox-pagination-link
186 |                 color: $searchbox-fg-pagination-item-active
187 |                 background-color: $searchbox-bg-pagination-item-active
188 | 
189 |         .searchbox-pagination-item.disabled
190 |             .searchbox-pagination-link
191 |                 cursor: not-allowed
192 |                 background-color: $searchbox-bg-pagination-item-disabled
193 | 
194 |         .searchbox-pagination-item:not(.active):not(.disabled)
195 |             .searchbox-pagination-link:hover
196 |                 background-color: $searchbox-bg-pagination-item-hover
197 | 
198 | @media screen and (max-width: $searchbox-breakpoint-width), screen and (max-height: $searchbox-breakpoint-height)
199 |     .searchbox .searchbox-container
200 |         top: 0
201 |         left: 0
202 |         width: 100%
203 |         height: 100%
204 |         border-radius: 0
205 | 


--------------------------------------------------------------------------------
/include/style/timeline.styl:
--------------------------------------------------------------------------------
 1 | /* ---------------------------------
 2 |  *          Archive Timeline
 3 |  * --------------------------------- */
 4 | $timeline-fg-line ?= $grey-lighter
 5 | $timeline-bg-line ?= $card-background-color
 6 | 
 7 | .timeline
 8 |     margin-left: 1rem
 9 |     padding: 1rem 0 0 1.5rem
10 |     border-left: 1px solid $timeline-fg-line
11 | 
12 |     .media
13 |         position: relative
14 | 
15 |         &:before, &:last-child:after
16 |             content: ''
17 |             display: block
18 |             position: absolute
19 |             left: calc(-.375rem - 1.5rem - .25px)
20 | 
21 |         &:before
22 |             width: .75rem
23 |             height: .75rem
24 |             top: calc(1rem + 1.5 * .85rem / 2 - .75rem / 2)
25 |             background: $timeline-fg-line
26 |             border-radius: 50%
27 | 
28 |         &:first-child:before
29 |             top: calc(1.5 * .85rem / 2 - .75rem / 2)
30 | 
31 |         &:last-child:after
32 |             width: .75rem
33 |             top: calc(1rem + 1.5 * .85rem / 2 + .75rem / 2)
34 |             bottom: 0
35 |             background: $timeline-bg-line
36 | 
37 |         &:first-child:last-child:after
38 |             top: calc(1.5 * .85rem / 2 + .75rem / 2)
39 | 


--------------------------------------------------------------------------------
/include/style/widget.styl:
--------------------------------------------------------------------------------
 1 | .widget
 2 |     .menu-list
 3 |         li
 4 |             ul
 5 |                 margin-right: 0
 6 | 
 7 |         .level
 8 |             margin-bottom: 0
 9 | 
10 |             .level-left, .level-right, .level-item
11 |                 flex-shrink: 1
12 | 
13 |             .level-left, .level-right
14 |                 align-items: flex-start
15 | 
16 |         .tag
17 |             background: $light-grey
18 |             color: $white-invert
19 | 
20 |     .tags
21 |         .tag:first-child
22 |             background: $primary
23 |             color: $primary-invert
24 | 
25 |         .tag:last-child
26 |             background: $light-grey
27 |             color: $white-invert
28 | 
29 | .level.is-multiline
30 |     flex-wrap: wrap
31 | 
32 | /* ---------------------------------
33 |  *      Table of Content Widget
34 |  * --------------------------------- */
35 | +mobile()
36 |     .widget.card#toc
37 |         display: none
38 |         position: fixed
39 |         margin: 1rem
40 |         left: 0
41 |         right: 0
42 |         bottom: 0
43 |         z-index: 100
44 | 
45 |         .card-content
46 |             padding: 0
47 | 
48 |         .menu
49 |             padding: 1.5rem
50 |             max-height: calc(100vh - 2rem)
51 |             overflow-y: auto
52 | 
53 |     #toc-mask
54 |         display: none
55 |         position: fixed
56 |         top: 0
57 |         left: 0
58 |         right: 0
59 |         bottom: 0
60 |         z-index: 99
61 |         background: rgba(0, 0, 0, .7)
62 | 
63 |     .widget.card#toc, #toc-mask
64 |         &.is-active
65 |             display: block


--------------------------------------------------------------------------------
/include/util/console.js:
--------------------------------------------------------------------------------
 1 | let chalk;
 2 | try {
 3 |     chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require
 4 | } catch (e) { }
 5 | 
 6 | module.exports = new Proxy({}, {
 7 |     get(obj, prop) {
 8 |         if (chalk) {
 9 |             return chalk[prop];
10 |         }
11 |         return function() {
12 |             return arguments.length === 1 ? arguments[0] : arguments;
13 |         };
14 |     }
15 | });
16 | 


--------------------------------------------------------------------------------
/languages/de.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Archiv'
 4 |         other: 'Archive'
 5 |     category:
 6 |         one: 'Kategorie'
 7 |         other: 'Kategorien'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tags'
11 |     post:
12 |         one: 'Seite'
13 |         other: 'Seiten'
14 |     page:
15 |         one: 'Page'
16 |         other: 'Pages'
17 |     prev: 'Zurück'
18 |     next: 'Weiter'
19 | widget:
20 |     follow: 'Folgen'
21 |     recents: 'Letzte Einträge'
22 |     links: 'Links'
23 |     catalogue: 'Katalog'
24 |     subscribe_email: 'Abonnieren Sie Updates'
25 |     subscribe: 'Abonnieren'
26 |     adsense: 'Werbung'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Gepostet vor&nbsp;%s'
30 |     updated_at: 'Aktualisiert vor&nbsp;%s'
31 |     more: 'Mehr lesen'
32 |     comments: 'Kommentare'
33 |     read_time: '%s lesen'
34 |     word_count:
35 |         one: 'Über %d Wort'
36 |         other: 'Über %d Wörter'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Gefällt Ihnen der Artikel? Unterstützen Sie den Autor mit'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Kauf mir einen Kaffee'
50 | plugin:
51 |     backtotop: 'Zurück nach oben'
52 |     visit_count: '%s&nbsp;Besuche'
53 |     visitor_count: 'Von %s Nutzern besucht'
54 |     cookie_consent:
55 |       message: Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern.
56 |       dismiss: Verstanden!
57 |       allow: Cookies zulassen
58 |       deny: Ablehnen
59 |       link: Mehr erfahren
60 |       policy: Cookie-Richtlinie
61 | search:
62 |     search: 'Suche'
63 |     hint: 'Tippen Sie etwas...'
64 |     no_result: 'Keine Ergebnisse für'
65 |     untitled: '(Ohne Titel)'
66 |     empty_preview: '(Keine Vorschau)'
67 | 


--------------------------------------------------------------------------------
/languages/en.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Archive'
 4 |         other: 'Archives'
 5 |     category:
 6 |         one: 'Category'
 7 |         other: 'Categories'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tags'
11 |     post:
12 |         one: 'Post'
13 |         other: 'Posts'
14 |     page:
15 |         one: 'Page'
16 |         other: 'Pages'
17 |     prev: 'Previous'
18 |     next: 'Next'
19 | widget:
20 |     follow: 'Follow'
21 |     recents: 'Recents'
22 |     links: 'Links'
23 |     catalogue: 'Catalogue'
24 |     subscribe_email: 'Subscribe for updates'
25 |     subscribe: 'Subscribe'
26 |     adsense: 'Advertisement'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Posted&nbsp;%s'
30 |     updated_at: 'Updated&nbsp;%s'
31 |     more: 'Read more'
32 |     comments: 'Comments'
33 |     read_time: '%s read'
34 |     word_count:
35 |         one: 'About %d word'
36 |         other: 'About %d words'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Like this article? Support the author with'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Buy me a coffee'
50 | plugin:
51 |     backtotop: 'Back to top'
52 |     visit_count: '%s&nbsp;visits'
53 |     visitor_count: 'Visited by %s users'
54 |     cookie_consent:
55 |       message: This website uses cookies to improve your experience.
56 |       dismiss: Got it!
57 |       allow: Allow cookies
58 |       deny: Decline
59 |       link: Learn more
60 |       policy: Cookie Policy
61 | search:
62 |     search: 'Search'
63 |     hint: 'Type something...'
64 |     no_result: 'No results for'
65 |     untitled: '(Untitled)'
66 |     empty_preview: '(No preview)'
67 | 


--------------------------------------------------------------------------------
/languages/es.yml:
--------------------------------------------------------------------------------
 1 | #By SrWoOoW
 2 | common:
 3 |     archive:
 4 |         one: 'Archivo'
 5 |         other: 'Archivos'
 6 |     category:
 7 |         one: 'Categoría'
 8 |         other: 'Categorías'
 9 |     tag:
10 |         one: 'Etiqueta'
11 |         other: 'Etiquetas'
12 |     post:
13 |         one: 'Entrada'
14 |         other: 'Entradas'
15 |     page:
16 |         one: 'Página'
17 |         other: 'Páginas'
18 |     prev: 'Anterior'
19 |     next: 'Siguiente'
20 | widget:
21 |     follow: 'SEGUIR'
22 |     recents: 'Recientes'
23 |     links: 'Enlaces'
24 |     catalogue: 'Catálogo'
25 |     subscribe_email: 'Suscríbete para recibir actualizaciones'
26 |     subscribe: 'Suscribir'
27 |     adsense: 'Anuncio'
28 |     followit: 'follow.it'
29 | article:
30 |     created_at: 'Publicado hace&nbsp;%s'
31 |     updated_at: 'Actualizado hace&nbsp;%s'
32 |     more: 'Leer más'
33 |     comments: 'Comentarios'
34 |     read_time: '%s de lectura'
35 |     word_count:
36 |         one: 'Aproximadamente %d palabra'
37 |         other: 'Aproximadamente %d palabras'
38 |     licensing:
39 |         author: 'Author'
40 |         created_at: 'Posted on'
41 |         updated_at: 'Updated on'
42 |         licensed_under: 'Licensed under'
43 | donate:
44 |     title: '¿Te gusta este artículo? Apoya al autor con'
45 |     afdian: 'Afdian.net'
46 |     alipay: 'Alipay'
47 |     wechat: 'Wechat'
48 |     paypal: 'Paypal'
49 |     patreon: 'Patreon'
50 |     buymeacoffee: 'Cómprame un café'
51 | plugin:
52 |     backtotop: 'Volver arriba'
53 |     visit_count: '%s&nbsp;visitas'
54 |     visitor_count: 'Visitado por %s usuarios'
55 |     cookie_consent:
56 |       message: Este sitio web utiliza cookies para mejorar su experiencia.
57 |       dismiss: ¡Entendido!
58 |       allow: Permitir cookies
59 |       deny: Descenso
60 |       link: Aprende más
61 |       policy: Política de cookies
62 | search:
63 |     search: 'Buscar'
64 |     hint: 'Teclea algo...'
65 |     no_result: 'No hay resultados para'
66 |     untitled: '(Sin título)'
67 |     empty_preview: '(Sin vista previa)'
68 | 


--------------------------------------------------------------------------------
/languages/fr.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Archive'
 4 |         other: 'Archives'
 5 |     category:
 6 |         one: 'Catégorie'
 7 |         other: 'Catégories'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tags'
11 |     post:
12 |         one: 'Article'
13 |         other: 'Articles'
14 |     page:
15 |         one: 'Page'
16 |         other: 'Pages'
17 |     prev: 'Préc'
18 |     next: 'Suiv'
19 | widget:
20 |     follow: 'Suivre'
21 |     recents: 'Récents'
22 |     links: 'Liens'
23 |     catalogue: 'Catalogue'
24 |     subscribe_email: 'Abonnez-vous aux mises à jour'
25 |     subscribe: 'Abonnez-vous'
26 |     adsense: 'Publicités'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Publié il y a&nbsp;%s'
30 |     updated_at: 'Mis à jour il y a&nbsp;%s'
31 |     more: 'Lire la suite'
32 |     comments: 'Commentaires'
33 |     read_time: '%s de lecture'
34 |     word_count:
35 |         one: 'Environ %d mot'
36 |         other: 'Environ %d mots'
37 |     licensing:
38 |         author: 'Auteur'
39 |         created_at: 'Posté le'
40 |         updated_at: 'Mis à jour le'
41 |         licensed_under: 'Licencié sous'
42 | donate:
43 |     title: "Vous aimez cet article? Soutenez l'auteur avec"
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Achetez-moi un café'
50 | plugin:
51 |     backtotop: 'Retour en haut'
52 |     visit_count: '%s&nbsp;visites'
53 |     visitor_count: 'Visité par %s utilisateurs'
54 |     cookie_consent:
55 |       message: 'Ce site Web utilise des cookies pour améliorer votre expérience.'
56 |       dismiss: "C'est bon"
57 |       allow: 'Autoriser les cookies'
58 |       deny: 'Refuser'
59 |       link: 'En savoir plus'
60 |       policy: 'Politique relative aux cookies'
61 | search:
62 |     search: 'Rechercher'
63 |     hint: 'Ecrivez quelque chose...'
64 |     no_result: 'Aucun résultat pour'
65 |     untitled: '(Sans titre)'
66 |     empty_preview: '(Pas de prévisualisation)'
67 | 


--------------------------------------------------------------------------------
/languages/id.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Arsip'
 4 |         other: 'Arsip'
 5 |     category:
 6 |         one: 'Kategori'
 7 |         other: 'Kategori'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tag'
11 |     post:
12 |         one: 'Artikel'
13 |         other: 'Artikel'
14 |     page:
15 |         one: 'Halaman'
16 |         other: 'Halaman'
17 |     prev: 'Sebelumnya'
18 |     next: 'Berikutnya'
19 | widget:
20 |     follow: 'IKUTI'
21 |     recents: 'Terbaru'
22 |     links: 'Tautan'
23 |     catalogue: 'Katalog'
24 |     subscribe_email: 'Berlangganan untuk pembaruan'
25 |     subscribe: 'Berlangganan'
26 |     adsense: 'Iklan'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Diposting&nbsp;%s'
30 |     updated_at: 'Diperbarui&nbsp;%s'
31 |     more: 'Selengkapnya'
32 |     comments: 'Komentar'
33 |     read_time: '%s membaca'
34 |     word_count:
35 |         one: 'Sekitar %d kata'
36 |         other: 'Sekitar %d kata'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Suka dengan artikel ini? Bantu penulis dengan donasi melalui'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Belikan aku kopi'
50 | plugin:
51 |     backtotop: 'Kembali ke atas'
52 |     visit_count: '%s&nbsp;kunjungan'
53 |     visitor_count: 'Dikunjungi oleh %s pengguna'
54 |     cookie_consent:
55 |       message: Situs web ini menggunakan cookie untuk meningkatkan pengalaman Anda.
56 |       dismiss: Mengerti!
57 |       allow: Izinkan cookie
58 |       deny: Menolak
59 |       link: Belajarlah lagi
60 |       policy: Kebijakan Cookie
61 | search:
62 |     search: 'Pencarian'
63 |     hint: 'Tulis Sesuatu..'
64 |     no_result: 'Tidak ada hasil untuk'
65 |     untitled: '(Tanpa judul)'
66 |     empty_preview: '(Tidak ada preview)'
67 | 


--------------------------------------------------------------------------------
/languages/it.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Archivio'
 4 |         other: 'Archivi'
 5 |     category:
 6 |         one: 'Categoria'
 7 |         other: 'Categorie'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tag'
11 |     post:
12 |         one: 'Articolo'
13 |         other: 'Articoli'
14 |     page:
15 |         one: 'Pagina'
16 |         other: 'Pagine'
17 |     prev: 'Precedente'
18 |     next: 'Successivo'
19 | widget:
20 |     follow: 'Segui'
21 |     recents: 'Recenti'
22 |     links: 'Collegamenti'
23 |     catalogue: 'Catalogo'
24 |     subscribe_email: 'Iscriviti per aggiornamenti'
25 |     subscribe: 'Iscriviti'
26 |     adsense: 'Pubblicità'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Pubblicato il&nbsp;%s'
30 |     updated_at: 'Aggiornato il&nbsp;%s'
31 |     more: 'Di più'
32 |     comments: 'Commenti'
33 |     read_time: '%s di lettura'
34 |     word_count:
35 |         one: 'Circa %d parola'
36 |         other: 'Circa %d parole'
37 |     licensing:
38 |         author: 'Autore'
39 |         created_at: 'Pubblicato il'
40 |         updated_at: 'Aggiornato il'
41 |         licensed_under: 'Licenza'
42 | donate:
43 |     title: "Ti è piaciuto questo articolo? Supporta l'autore con"
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Buy me a coffee'
50 | plugin:
51 |     backtotop: 'Torna su'
52 |     visit_count: '%s&nbsp;visite'
53 |     visitor_count: 'Visto da %s usenti'
54 |     cookie_consent:
55 |       message: Questo sito usa i cookie per migliorare la tua esperienza.
56 |       dismiss: "D'accordo!"
57 |       allow: Accetta i cookie
58 |       deny: Rifiuta
59 |       link: Più informazioni
60 |       policy: Politica dei cookie
61 | search:
62 |     search: 'Cerca'
63 |     hint: 'Digita qualcosa...'
64 |     no_result: 'Nessun risultato per'
65 |     untitled: '(Senza titolo)'
66 |     empty_preview: '(Senza anteprima)'
67 | 


--------------------------------------------------------------------------------
/languages/ja.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'アーカイブ'
 4 |         other: 'アーカイブ'
 5 |     category:
 6 |         one: 'カテゴリ'
 7 |         other: 'カテゴリ'
 8 |     tag:
 9 |         one: 'タグ'
10 |         other: 'タグ'
11 |     post:
12 |         one: '投稿'
13 |         other: '投稿'
14 |     page:
15 |         one: 'ページ'
16 |         other: 'ページ'
17 |     prev: '前'
18 |     next: '次'
19 | widget:
20 |     follow: 'フォローする'
21 |     recents: '最近の記事'
22 |     links: 'リンク'
23 |     catalogue: 'カタログ'
24 |     subscribe_email: '更新を購読する'
25 |     subscribe: '購読する'
26 |     adsense: '広告'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: '%sに投稿'
30 |     updated_at: '%sに更新'
31 |     more: '続きを読む'
32 |     comments: 'コメント'
33 |     read_time: '%sで読む'
34 |     word_count:
35 |         one: '約%d語'
36 |         other: '約%d語'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'この記事は気に入りましたか? 著者をサポートする'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'コーヒーを買って'
50 | plugin:
51 |     backtotop: 'トップに戻る'
52 |     visit_count: '%s回の訪問'
53 |     visitor_count: '%s人のユーザーがアクセス'
54 |     cookie_consent:
55 |       message: このウェブサイトはあなたの経験を改善するためにCookieを使用しています。
56 |       dismiss: 了解しました
57 |       allow: Cookiesを許可する
58 |       deny: 拒否する
59 |       link: もっと詳しく知る
60 |       policy: Cookieポリシー
61 | search:
62 |     search: '検索'
63 |     hint: '何かを入力してください...'
64 |     no_result: 'の結果はありません'
65 |     untitled: '(無題)'
66 |     empty_preview: '(プレビューなし)'
67 | 


--------------------------------------------------------------------------------
/languages/ko.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: '아카이브'
 4 |         other: '아카이브'
 5 |     category:
 6 |         one: '카테고리'
 7 |         other: '카테고리'
 8 |     tag:
 9 |         one: '태그'
10 |         other: '태그'
11 |     post:
12 |         one: '포스트'
13 |         other: '포스트'
14 |     page:
15 |         one: '페이지'
16 |         other: '페이지'
17 |     prev: '이전'
18 |     next: '다음'
19 | widget:
20 |     follow: '팔로우'
21 |     recents: '최근 글'
22 |     links: '링크'
23 |     catalogue: '카탈로그'
24 |     subscribe_email: '업데이트 소식 받기'
25 |     subscribe: '구독'
26 |     adsense: '광고'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: '%s&nbsp;게시 됨'
30 |     updated_at: '%s&nbsp;업데이트 됨'
31 |     more: '자세히 보기'
32 |     comments: '댓글'
33 |     read_time: '%s안에 읽기'
34 |     word_count:
35 |         one: '약 %d 단어'
36 |         other: '약 %d 단어'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: '이 글이 마음에 드시나요? 다음을 통해 후원하실 수 있습니다: '
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: '커피 한 잔 사주기'
50 | plugin:
51 |     backtotop: '맨 위로'
52 |     visit_count: '%s회 방문'
53 |     visitor_count: '%s명의 사용자가 방문 함'
54 |     cookie_consent:
55 |         message: 이 웹 사이트는 귀하의 경험을 향상시키기 위해 Cookie를 사용합니다.
56 |         dismiss: 무시
57 |         allow: 허용
58 |         deny: 거부
59 |         link: 더 알아보기
60 |         policy: Cookie 정책
61 | search:
62 |     search: '검색'
63 |     hint: '입력 하세요...'
64 |     no_result: '에 대한 결과 없음'
65 |     untitled: '(제목 없음)'
66 |     empty_preview: '(미리보기 없음)'
67 | 


--------------------------------------------------------------------------------
/languages/pl.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Archiwum'
 4 |         other: 'Archiwum'
 5 |     category:
 6 |         one: 'Kategoria'
 7 |         other: 'Kategorie'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tagi'
11 |     post:
12 |         one: 'Artykuł'
13 |         other: 'Artykuły'
14 |     page:
15 |         one: 'Strona'
16 |         other: 'Strony'
17 |     prev: 'Poprzedni'
18 |     next: 'Następny'
19 | widget:
20 |     follow: 'SUBSKRYBUJ'
21 |     recents: 'Najnowsze wpisy'
22 |     links: 'Linki'
23 |     catalogue: 'Spis treści'
24 |     subscribe_email: 'Zapisz się, aby otrzymywać aktualizacje'
25 |     subscribe: 'Subskrybuj'
26 |     adsense: 'Reklama'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Opublikowano&nbsp;%s'
30 |     updated_at: 'Zaktualizowano&nbsp;%s'
31 |     more: 'Czytaj dalej'
32 |     comments: 'Komentarze'
33 |     read_time: '%s czytania'
34 |     word_count:
35 |         one: 'Około %d słowa'
36 |         other: 'Około %d słów'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Podoba Ci się ten artykuł? Wesprzyj autora za pomocą'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Kup mi kawę'
50 | plugin:
51 |     backtotop: 'Powrót do góry'
52 |     visit_count: '%s&nbsp;wizyty'
53 |     visitor_count: 'Odwiedzone przez %s użytkowników'
54 |     cookie_consent:
55 |       message: Ta strona korzysta z plików cookie, aby poprawić Twoje doświadczenia.
56 |       dismiss: Rozumiem!
57 |       allow: Zezwól na pliki cookie
58 |       deny: Odrzucać
59 |       link: Ucz się więcej
60 |       policy: Polityka Cookie
61 | search:
62 |     search: 'szukaj'
63 |     hint: 'Wpisz coś...'
64 |     no_result: 'Brak wyników dla'
65 |     untitled: '(Bez tytułu)'
66 |     empty_preview: '(Brak podglądu)'
67 | 


--------------------------------------------------------------------------------
/languages/pt-BR.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Arquivo'
 4 |         other: 'Arquivos'
 5 |     category:
 6 |         one: 'Categoria'
 7 |         other: 'Categorias'
 8 |     tag:
 9 |         one: 'Tag'
10 |         other: 'Tags'
11 |     post:
12 |         one: 'Artigo'
13 |         other: 'Artigos'
14 |     page:
15 |         one: 'Página'
16 |         other: 'Páginas'
17 |     prev: 'Anterior'
18 |     next: 'Próximo'
19 | widget:
20 |     follow: 'Seguir'
21 |     recents: 'Recentes'
22 |     links: 'Links'
23 |     catalogue: 'Catálogo'
24 |     subscribe_email: 'Subscrição de atualizações'
25 |     subscribe: 'Se inscrever'
26 |     adsense: 'Anúncio'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Postado&nbsp;%s'
30 |     updated_at: 'Atualizado&nbsp;%s'
31 |     more: 'Ler Mais'
32 |     comments: 'Comentarios'
33 |     read_time: '%s lidos'
34 |     word_count:
35 |         one: 'Cerca de %d palavra'
36 |         other: 'Cerca de %d palavras'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Gostou deste artigo? Apoie o autor com'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Me compra um café'
50 | plugin:
51 |     backtotop: 'De volta ao topo'
52 |     visit_count: '%s&nbsp;visitas'
53 |     visitor_count: 'Visitado por %s usuários'
54 |     cookie_consent:
55 |       message: Este site usa cookies para melhorar sua experiência.
56 |       dismiss: Entendi!
57 |       allow: Permitir cookies
58 |       deny: Declínio
59 |       link: Saber mais
60 |       policy: Política de Cookies
61 | search:
62 |     search: 'Procurar'
63 |     hint: 'Digite alguma coisa...'
64 |     no_result: 'Sem resultados para'
65 |     untitled: '(Sem título)'
66 |     empty_preview: '(Não há visualização)'
67 | 


--------------------------------------------------------------------------------
/languages/ru.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'архив'
 4 |         other: 'архивы'
 5 |     category:
 6 |         one: 'категории'
 7 |         other: 'категории'
 8 |     tag:
 9 |         one: 'тег'
10 |         other: 'теги'
11 |     post:
12 |         one: 'пост'
13 |         other: 'посты'
14 |     page:
15 |         one: 'страница'
16 |         other: 'страницы'
17 |     prev: 'Назад'
18 |     next: 'Далее'
19 | widget:
20 |     follow: 'Подписаться'
21 |     recents: 'недавние'
22 |     links: 'ссылки'
23 |     catalogue: 'Каталог'
24 |     subscribe_email: 'Подпишитесь на обновления'
25 |     subscribe: 'Подписывайся'
26 |     adsense: 'Рекламное объявление'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Опубликовано&nbsp;%s'
30 |     updated_at: 'Обновлено&nbsp;%s'
31 |     more: 'Читать дальше'
32 |     comments: 'Комментарии'
33 |     read_time: '%s на чтение'
34 |     word_count:
35 |         one: 'Около %d слова'
36 |         other: 'Примерно %d слова'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Понравилась эта статья? Поддержите автора'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Купи мне кофе'
50 | plugin:
51 |     backtotop: 'Вернуться наверх'
52 |     visit_count: '%s&nbsp;посещения'
53 |     visitor_count: 'Посетили %s пользователя'
54 |     cookie_consent:
55 |       message: Этот веб-сайт использует файлы cookie для улучшения вашего опыта.
56 |       dismiss: Понял!
57 |       allow: Разрешить cookies
58 |       deny: Отказаться
59 |       link: Учить больше
60 |       policy: Политика Cookie
61 | search:
62 |     search: 'Поиск'
63 |     hint: 'Введите что-нибудь...'
64 |     no_result: 'Нет результатов по запросу'
65 |     untitled: '(Без названия)'
66 |     empty_preview: '(Нет предварительного просмотра)'
67 | 


--------------------------------------------------------------------------------
/languages/sv.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Arkiv'
 4 |         other: 'Arkiv'
 5 |     category:
 6 |         one: 'Kategori'
 7 |         other: 'Kategorier'
 8 |     tag:
 9 |         one: 'Etikett'
10 |         other: 'Etiketter'
11 |     post:
12 |         one: 'Inlägg'
13 |         other: 'Inlägg'
14 |     page:
15 |         one: 'Sida'
16 |         other: 'Sidor'
17 |     prev: 'Föregående'
18 |     next: 'Nästa'
19 | widget:
20 |     follow: 'Följ'
21 |     recents: 'Senaste'
22 |     links: 'Länkar'
23 |     catalogue: 'Katalog'
24 |     subscribe_email: 'Prenumerera för uppdateringar'
25 |     subscribe: 'Prenumerera'
26 |     adsense: 'Marknadsföring'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Publicerad&nbsp;%s'
30 |     updated_at: 'Uppdaterad&nbsp;%s'
31 |     more: 'Läs mer'
32 |     comments: 'Kommentarer'
33 |     read_time: '%s lästid'
34 |     word_count:
35 |         one: 'Cirka %d ord'
36 |         other: 'Cirka %d ord'
37 |     licensing:
38 |         author: 'Författare'
39 |         created_at: 'Publicerad'
40 |         updated_at: 'Uppdaterad'
41 |         licensed_under: 'Licensierad under'
42 | donate:
43 |     title: 'Tycker du om den här artikeln? Stöd författaren genom'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Köp mig en kaffe'
50 | plugin:
51 |     backtotop: 'Tillbaka till början'
52 |     visit_count: '%s&nbsp;besök'
53 |     visitor_count: 'Besökt av %s användare'
54 |     cookie_consent:
55 |       message: Den här hemsidan använder kakor för att förbättra funktionen.
56 |       dismiss: Jag förstår!
57 |       allow: Tillåt kakor
58 |       deny: Avböj kakor
59 |       link: Lär mer
60 |       policy: Kakpolicy
61 | search:
62 |     search: 'Sök'
63 |     hint: 'Skriv någonting...'
64 |     no_result: 'Inga sökresultat för'
65 |     untitled: '(Utan titel)'
66 |     empty_preview: '(Ingen förhandsvisning)'
67 | 


--------------------------------------------------------------------------------
/languages/tk.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Arhiw'
 4 |         other: 'Arhiwler'
 5 |     category:
 6 |         one: 'Bölüm'
 7 |         other: 'Bölümler'
 8 |     tag:
 9 |         one: 'Teg'
10 |         other: 'Tegler'
11 |     post:
12 |         one: 'Post'
13 |         other: 'Postlar'
14 |     page:
15 |         one: 'Sahypa'
16 |         other: 'Sahypalar'
17 |     prev: 'Öňki'
18 |     next: 'Indiki'
19 | widget:
20 |     follow: 'Abuna bol'
21 |     recents: 'Täze habarlar'
22 |     links: 'Linkler'
23 |     catalogue: 'Katalog'
24 |     subscribe_email: 'Täzelikler üçin ýazyl'
25 |     subscribe: 'Ýazyl'
26 |     adsense: 'Mahabat'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Paýlaşyldy&nbsp;%s'
30 |     updated_at: 'Üýtgedildi&nbsp;%s'
31 |     more: 'Dowamy...'
32 |     comments: 'Kommentariýa'
33 |     read_time: '%s okaldy'
34 |     word_count:
35 |         one: 'Ortaça %d söz'
36 |         other: 'Ortaça %d söz'
37 |     licensing:
38 |         author: 'Awtor'
39 |         created_at: 'Paýlaşdy'
40 |         updated_at: 'Üýtgetdi'
41 |         licensed_under: 'Resmileşdirilen'
42 | donate:
43 |     title: 'Haladynmy? Awtory gollaň'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Buy me a coffee'
50 | plugin:
51 |     backtotop: 'Ýokaryk'
52 |     visit_count: '%s&nbsp;görüldi'
53 |     visitor_count: '%s adam gördi'
54 |     cookie_consent:
55 |       message: Bu web saýt siziň üçin kuki ulanýar.
56 |       dismiss: Düşündim!
57 |       allow: Kukini kabul et!
58 |       deny: Närazylyk bildir
59 |       link: Dowamy...
60 |       policy: Kuki syýasaty
61 | search:
62 |     search: 'Gözle'
63 |     hint: 'Birzatlar ýazyň...'
64 |     no_result: 'Tapylmady'
65 |     untitled: 'Atlandyrylmadyk'
66 |     empty_preview: 'Boş'
67 | 


--------------------------------------------------------------------------------
/languages/tr.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Arşiv'
 4 |         other: 'Arşivler'
 5 |     category:
 6 |         one: 'Kategori'
 7 |         other: 'Kategoriler'
 8 |     tag:
 9 |         one: 'Etiket'
10 |         other: 'Etiketler'
11 |     post:
12 |         one: 'Gönderi'
13 |         other: 'Gönderiler'
14 |     page:
15 |         one: 'Sayfa'
16 |         other: 'Sayfalar'
17 |     prev: 'Önceki'
18 |     next: 'Sonraki'
19 | widget:
20 |     follow: 'TAKİP ET'
21 |     recents: 'Son'
22 |     links: 'Linkler'
23 |     catalogue: 'Katalog'
24 |     subscribe_email: 'Güncellemeler için abone olun'
25 |     subscribe: 'Abone ol'
26 |     adsense: 'İlan'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: '%s&nbsp;yayınlandı'
30 |     updated_at: '%s&nbsp;güncellendi'
31 |     more: 'Daha fazla oku'
32 |     comments: 'Yorumlar'
33 |     read_time: '%s okuma süresi'
34 |     word_count:
35 |         one: 'Yaklaşık %d kelime'
36 |         other: 'Yaklaşık %d kelime'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Bu makaleyi beğendiniz mi? Yazarı şununla destekleyin'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Bana bir kahve al'
50 | plugin:
51 |     backtotop: 'Başa dönüş'
52 |     visit_count: '%s&nbsp;ziyaret'
53 |     visitor_count: '%s kullanıcı tarafından ziyaret edildi'
54 |     cookie_consent:
55 |       message: Bu web sitesi, deneyiminizi geliştirmek için çerezler kullanır.
56 |       dismiss: Anladım!
57 |       allow: Çerezlere izin ver
58 |       deny: Reddet
59 |       link: Daha fazla bilgi edin
60 |       policy: Çerez politikası
61 | search:
62 |     search: 'Ara'
63 |     hint: 'Bir şeyler yaz...'
64 |     no_result: 'İçin sonuç yok'
65 |     untitled: '(Başlıksız)'
66 |     empty_preview: '(Önizleme yok)'
67 | 


--------------------------------------------------------------------------------
/languages/vn.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: 'Lưu trữ'
 4 |         other: 'Lưu trữ'
 5 |     category:
 6 |         one: 'Thể loại'
 7 |         other: 'Thể loại'
 8 |     tag:
 9 |         one: 'Nhãn'
10 |         other: 'Nhãn'
11 |     post:
12 |         one: 'Bài viết'
13 |         other: 'Bài viết'
14 |     page:
15 |         one: 'Trang'
16 |         other: 'Trang'
17 |     prev: 'Trước'
18 |     next: 'Sau'
19 | widget:
20 |     follow: 'Theo dõi'
21 |     recents: 'Gần đây'
22 |     links: 'Link'
23 |     catalogue: 'Mục lục'
24 |     subscribe_email: 'Theo dõi các bản cập nhật'
25 |     subscribe: 'Theo dõi'
26 |     adsense: 'Quảng cáo'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: 'Đã đăng&nbsp;%s'
30 |     updated_at: 'Đã cập nhật&nbsp;%s'
31 |     more: 'Đọc thêm'
32 |     comments: 'Bình luận'
33 |     read_time: '%s đọc'
34 |     word_count:
35 |         one: 'Khoảng %d từ'
36 |         other: 'Khoảng %d từ'
37 |     licensing:
38 |         author: 'Author'
39 |         created_at: 'Posted on'
40 |         updated_at: 'Updated on'
41 |         licensed_under: 'Licensed under'
42 | donate:
43 |     title: 'Bạn đọc có thể ủng hộ blog qua'
44 |     afdian: 'Afdian.net'
45 |     alipay: 'Alipay'
46 |     wechat: 'Wechat'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: 'Mua cho tôi một ly cà phê'
50 | plugin:
51 |     backtotop: 'Trở lai đầu trang'
52 |     visit_count: '%s&nbsp;Bạn đọc'
53 |     visitor_count: 'Thăm bởi %s bạn đọc'
54 |     cookie_consent:
55 |       message: Trang web này sử dụng cookie để cải thiện trải nghiệm của bạn.
56 |       dismiss: Hiểu rồi!
57 |       allow: Cho phép cookie
58 |       deny: Từ chối
59 |       link: Tìm hiểu thêm
60 |       policy: Chính sách Cookie
61 | search:
62 |     search: 'Tìm kiếm'
63 |     hint: 'Gõ gì đó...'
64 |     no_result: 'Không có kết quả cho'
65 |     untitled: '(Không có tiêu đề)'
66 |     empty_preview: '(Không có xem trước)'
67 | 


--------------------------------------------------------------------------------
/languages/zh-CN.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: '归档'
 4 |         other: '归档'
 5 |     category:
 6 |         one: '分类'
 7 |         other: '分类'
 8 |     tag:
 9 |         one: '标签'
10 |         other: '标签'
11 |     post:
12 |         one: '文章'
13 |         other: '文章'
14 |     page:
15 |         one: '页面'
16 |         other: '页面'
17 |     prev: '上一页'
18 |     next: '下一页'
19 | widget:
20 |     follow: '关注我'
21 |     recents: '最新文章'
22 |     links: '链接'
23 |     catalogue: '目录'
24 |     subscribe_email: '订阅更新'
25 |     subscribe: '订阅'
26 |     adsense: '广告'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: '%s发表'
30 |     updated_at: '%s更新'
31 |     more: '阅读更多'
32 |     comments: '评论'
33 |     read_time: '%s读完'
34 |     word_count:
35 |         one: '大约%d个字'
36 |         other: '大约%d个字'
37 |     licensing:
38 |         author: '作者'
39 |         created_at: '发布于'
40 |         updated_at: '更新于'
41 |         licensed_under: '许可协议'
42 | donate:
43 |     title: '喜欢这篇文章?打赏一下作者吧'
44 |     afdian: '爱发电'
45 |     alipay: '支付宝'
46 |     wechat: '微信'
47 |     paypal: 'Paypal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: '送我杯咖啡'
50 | plugin:
51 |     backtotop: '回到顶端'
52 |     visit_count: '%s次访问'
53 |     visitor_count: '共%s个访客'
54 |     cookie_consent:
55 |       message: 此网站使用Cookie来改善您的体验。
56 |       dismiss: 知道了!
57 |       allow: 允许使用Cookie
58 |       deny: 拒绝
59 |       link: 了解更多
60 |       policy: Cookie政策
61 | search:
62 |     search: '搜索'
63 |     hint: '想要查找什么...'
64 |     no_result: '未找到搜索结果'
65 |     untitled: '(无标题)'
66 |     empty_preview: '(无内容预览)'
67 | 


--------------------------------------------------------------------------------
/languages/zh-TW.yml:
--------------------------------------------------------------------------------
 1 | common:
 2 |     archive:
 3 |         one: '彙整'
 4 |         other: '彙整'
 5 |     category:
 6 |         one: '分類'
 7 |         other: '分類'
 8 |     tag:
 9 |         one: '標籤'
10 |         other: '標籤'
11 |     post:
12 |         one: '文章'
13 |         other: '文章'
14 |     page:
15 |         one: '頁面'
16 |         other: '頁面'
17 |     prev: '上一頁'
18 |     next: '下一頁'
19 | widget:
20 |     follow: '追蹤'
21 |     recents: '最新文章'
22 |     links: '連結'
23 |     catalogue: '文章目錄'
24 |     subscribe_email: '訂閱 Email'
25 |     subscribe: '訂閱'
26 |     adsense: '廣告'
27 |     followit: 'follow.it'
28 | article:
29 |     created_at: '%s發表'
30 |     updated_at: '%s更新'
31 |     more: '繼續閱讀'
32 |     comments: '評論'
33 |     read_time: '%s讀完'
34 |     word_count:
35 |         one: '大約%d個字'
36 |         other: '大約%d個字'
37 |     licensing:
38 |         author: '作者'
39 |         created_at: '發表於'
40 |         updated_at: '更新於'
41 |         licensed_under: '許可協議'
42 | donate:
43 |     title: '喜歡這篇文章嗎? 贊助一下作者吧!'
44 |     afdian: '愛發電'
45 |     alipay: '支付寶'
46 |     wechat: 'WeChat'
47 |     paypal: 'PayPal'
48 |     patreon: 'Patreon'
49 |     buymeacoffee: '送我杯咖啡'
50 | plugin:
51 |     backtotop: '回到頁首'
52 |     visit_count: '%s次訪問'
53 |     visitor_count: '共%s個訪客'
54 |     cookie_consent:
55 |       message: 此網站使用Cookie來改善您的體驗。
56 |       dismiss: 知道了!
57 |       allow: 允許使用Cookie
58 |       deny: 拒絕
59 |       link: 了解更多
60 |       policy: Cookie政策
61 | search:
62 |     search: '搜尋'
63 |     hint: '請輸入關鍵字...'
64 |     no_result: '未找到搜索結果'
65 |     untitled: '(無標題)'
66 |     empty_preview: '(無內容預覽)'
67 | 


--------------------------------------------------------------------------------
/layout/archive.jsx:
--------------------------------------------------------------------------------
 1 | const moment = require('moment');
 2 | const { Component, Fragment } = require('inferno');
 3 | const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
 4 | const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
 5 | const ArticleMedia = require('hexo-component-inferno/lib/view/common/article_media');
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { config, page, helper } = this.props;
10 |         const { url_for, __, date_xml, date } = helper;
11 | 
12 |         const language = toMomentLocale(page.lang || page.language || config.language);
13 | 
14 |         function renderArticleList(posts, year, month = null) {
15 |             const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));
16 | 
17 |             return <div class="card">
18 |                 <div class="card-content">
19 |                     <h3 class="tag is-primary">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
20 |                     <div class="timeline">
21 |                         {posts.map(post => {
22 |                             const categories = post.categories.map(category => ({
23 |                                 url: url_for(category.path),
24 |                                 name: category.name
25 |                             }));
26 |                             return <ArticleMedia
27 |                                 url={url_for(post.link || post.path)}
28 |                                 title={post.title}
29 |                                 date={date(post.date)}
30 |                                 dateXml={date_xml(post.date)}
31 |                                 categories={categories}
32 |                                 thumbnail={post.thumbnail ? url_for(post.thumbnail) : null} />;
33 |                         })}
34 |                     </div>
35 |                 </div>
36 |             </div>;
37 |         }
38 | 
39 |         let articleList;
40 |         if (!page.year) {
41 |             const years = {};
42 |             page.posts.each(p => { years[p.date.year()] = null; });
43 |             articleList = Object.keys(years).sort((a, b) => b - a).map(year => {
44 |                 const posts = page.posts.filter(p => p.date.year() === parseInt(year, 10));
45 |                 return renderArticleList(posts, year, null);
46 |             });
47 |         } else {
48 |             articleList = renderArticleList(page.posts, page.year, page.month);
49 |         }
50 | 
51 |         return <Fragment>
52 |             {articleList}
53 |             {page.total > 1 ? <Paginator
54 |                 current={page.current}
55 |                 total={page.total}
56 |                 baseUrl={page.base}
57 |                 path={config.pagination_dir}
58 |                 urlFor={url_for}
59 |                 prevTitle={__('common.prev')}
60 |                 nextTitle={__('common.next')} /> : null}
61 |         </Fragment>;
62 |     }
63 | };
64 | 


--------------------------------------------------------------------------------
/layout/categories.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const Categories = require('hexo-component-inferno/lib/view/widget/categories');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { site, page, helper } = this.props;
 7 | 
 8 |         return <Categories.Cacheable site={site} page={page} helper={helper} />;
 9 |     }
10 | };
11 | 


--------------------------------------------------------------------------------
/layout/category.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | const Index = require('./index');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { config, page, helper } = this.props;
 7 |         const { url_for, _p } = helper;
 8 | 
 9 |         return <Fragment>
10 |             <div class="card">
11 |                 <div class="card-content">
12 |                     <nav class="breadcrumb" aria-label="breadcrumbs">
13 |                         <ul>
14 |                             <li><a href={url_for('/categories/')}>{_p('common.category', Infinity)}</a></li>
15 |                             {page.parents.map(category => {
16 |                                 return <li><a href={url_for(category.path)}>{category.name}</a></li>;
17 |                             })}
18 |                             <li class="is-active"><a href="#" aria-current="page">{page.category}</a></li>
19 |                         </ul>
20 |                     </nav>
21 |                 </div>
22 |             </div>
23 |             <Index config={config} page={page} helper={helper} />
24 |         </Fragment>;
25 |     }
26 | };
27 | 


--------------------------------------------------------------------------------
/layout/comment/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/layout/comment/.gitkeep


--------------------------------------------------------------------------------
/layout/common/article.jsx:
--------------------------------------------------------------------------------
  1 | const moment = require('moment');
  2 | const { Component, Fragment } = require('inferno');
  3 | const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
  4 | const Share = require('./share');
  5 | const Donates = require('./donates');
  6 | const Comment = require('./comment');
  7 | const ArticleLicensing = require('hexo-component-inferno/lib/view/misc/article_licensing');
  8 | 
  9 | /**
 10 |  * Get the word count of text.
 11 |  */
 12 | function getWordCount(content) {
 13 |     if (typeof content === 'undefined') {
 14 |         return 0;
 15 |     }
 16 |     content = content.replace(/<\/?[a-z][^>]*>/gi, '');
 17 |     content = content.trim();
 18 |     return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
 19 | }
 20 | 
 21 | module.exports = class extends Component {
 22 |     render() {
 23 |         const { config, helper, page, index } = this.props;
 24 |         const { article, plugins } = config;
 25 |         const { url_for, date, date_xml, __, _p } = helper;
 26 | 
 27 |         const defaultLanguage = Array.isArray(config.language) && config.language.length ? config.language[0] : config.language;
 28 | 
 29 |         const indexLanguage = toMomentLocale(defaultLanguage || 'en');
 30 |         const language = toMomentLocale(page.lang || page.language || defaultLanguage || 'en');
 31 |         const cover = page.cover ? url_for(page.cover) : null;
 32 |         const updateTime = article && article.update_time !== undefined ? article.update_time : true;
 33 |         const isUpdated = page.updated && !moment(page.date).isSame(moment(page.updated));
 34 |         const shouldShowUpdated = page.updated && ((updateTime === 'auto' && isUpdated) || updateTime === true);
 35 | 
 36 |         return <Fragment>
 37 |             {/* Main content */}
 38 |             <div class="card">
 39 |                 {/* Thumbnail */}
 40 |                 {cover ? <div class="card-image">
 41 |                     {index ? <a href={url_for(page.link || page.path)} class="image is-7by3">
 42 |                         <img class="fill" src={cover} alt={page.title || cover} />
 43 |                     </a> : <span class="image is-7by3">
 44 |                         <img class="fill" src={cover} alt={page.title || cover} />
 45 |                     </span>}
 46 |                 </div> : null}
 47 |                 <article class={`card-content article${'direction' in page ? ' ' + page.direction : ''}`} role="article">
 48 |                     {/* Metadata */}
 49 |                     {page.layout !== 'page' ? <div class="article-meta is-size-7 is-uppercase level is-mobile">
 50 |                         <div class="level-left">
 51 |                             {/* PIN Icon */}
 52 |                             {page.top ? <i class="fas fa-thumbtack level-item" title="Pinned"></i> : null}
 53 |                             {/* Creation Date */}
 54 |                             {page.date && <span class="level-item" dangerouslySetInnerHTML={{
 55 |                                 __html: _p('article.created_at', `<time dateTime="${date_xml(page.date)}" title="${new Date(page.date).toLocaleString()}">${date(page.date)}</time>`)
 56 |                             }}></span>}
 57 |                             {/* Last Update Date */}
 58 |                             {shouldShowUpdated && <span class="level-item" dangerouslySetInnerHTML={{
 59 |                                 __html: _p('article.updated_at', `<time dateTime="${date_xml(page.updated)}" title="${new Date(page.updated).toLocaleString()}">${date(page.updated)}</time>`)
 60 |                             }}></span>}
 61 |                             {/* author */}
 62 |                             {page.author ? <span class="level-item"> {page.author} </span> : null}
 63 |                             {/* Categories */}
 64 |                             {page.categories && page.categories.length ? <span class="level-item">
 65 |                                 {(() => {
 66 |                                     const categories = [];
 67 |                                     page.categories.forEach((category, i) => {
 68 |                                         categories.push(<a class="link-muted" href={url_for(category.path)}>{category.name}</a>);
 69 |                                         if (i < page.categories.length - 1) {
 70 |                                             categories.push(<span>&nbsp;/&nbsp;</span>);
 71 |                                         }
 72 |                                     });
 73 |                                     return categories;
 74 |                                 })()}
 75 |                             </span> : null}
 76 |                             {/* Read time */}
 77 |                             {article && article.readtime && article.readtime === true ? <span class="level-item">
 78 |                                 {(() => {
 79 |                                     const words = getWordCount(page._content);
 80 |                                     const time = moment.duration((words / 150.0) * 60, 'seconds');
 81 |                                     return `${_p('article.read_time', time.locale(index ? indexLanguage : language).humanize())} (${_p('article.word_count', words)})`;
 82 |                                 })()}
 83 |                             </span> : null}
 84 |                             {/* Visitor counter */}
 85 |                             {!index && plugins && plugins.busuanzi === true ? <span class="level-item" id="busuanzi_container_page_pv" dangerouslySetInnerHTML={{
 86 |                                 __html: _p('plugin.visit_count', '<span id="busuanzi_value_page_pv">0</span>')
 87 |                             }}></span> : null}
 88 |                         </div>
 89 |                     </div> : null}
 90 |                     {/* Title */}
 91 |                     {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}
 92 |                     {page.title !== '' && !index ? <h1 class="title is-3 is-size-4-mobile">{page.title}</h1> : null}
 93 |                     {/* Content/Excerpt */}
 94 |                     <div class="content" dangerouslySetInnerHTML={{ __html: index && page.excerpt ? page.excerpt : page.content }}></div>
 95 |                     {/* Licensing block */}
 96 |                     {!index && article && article.licenses && Object.keys(article.licenses)
 97 |                         ? <ArticleLicensing.Cacheable page={page} config={config} helper={helper} /> : null}
 98 |                     {/* Tags */}
 99 |                     {!index && page.tags && page.tags.length ? <div class="article-tags is-size-7 mb-4">
100 |                         <span class="mr-2">#</span>
101 |                         {page.tags.map(tag => {
102 |                             return <a class="link-muted mr-2" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
103 |                         })}
104 |                     </div> : null}
105 |                     {/* "Read more" button */}
106 |                     {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}
107 |                     {/* Share button */}
108 |                     {!index ? <Share config={config} page={page} helper={helper} /> : null}
109 |                 </article>
110 |             </div>
111 |             {/* Donate button */}
112 |             {!index ? <Donates config={config} helper={helper} /> : null}
113 |             {/* Post navigation */}
114 |             {!index && (page.prev || page.next) ? <nav class="post-navigation mt-4 level is-mobile">
115 |                 {page.prev ? <div class="level-start">
116 |                     <a class={`article-nav-prev level level-item${!page.prev ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.prev.path)}>
117 |                         <i class="level-item fas fa-chevron-left"></i>
118 |                         <span class="level-item">{page.prev.title}</span>
119 |                     </a>
120 |                 </div> : null}
121 |                 {page.next ? <div class="level-end">
122 |                     <a class={`article-nav-next level level-item${!page.next ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.next.path)}>
123 |                         <span class="level-item">{page.next.title}</span>
124 |                         <i class="level-item fas fa-chevron-right"></i>
125 |                     </a>
126 |                 </div> : null}
127 |             </nav> : null}
128 |             {/* Comment */}
129 |             {!index ? <Comment config={config} page={page} helper={helper} /> : null}
130 |         </Fragment>;
131 |     }
132 | };
133 | 


--------------------------------------------------------------------------------
/layout/common/comment.jsx:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | const { Component } = require('inferno');
 3 | const view = require('hexo-component-inferno/lib/core/view');
 4 | 
 5 | const logger = createLogger.default();
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { config, page, helper } = this.props;
10 |         const { __ } = helper;
11 |         const { comment } = config;
12 |         if (!comment || typeof comment.type !== 'string') {
13 |             return null;
14 |         }
15 | 
16 |         return <div class="card" id="comments">
17 |             <div class="card-content">
18 |                 <h3 class="title is-5">{__('article.comments')}</h3>
19 |                 {(() => {
20 |                     try {
21 |                         let Comment = view.require('comment/' + comment.type);
22 |                         Comment = Comment.Cacheable ? Comment.Cacheable : Comment;
23 |                         return <Comment config={config} page={page} helper={helper} comment={comment} />;
24 |                     } catch (e) {
25 |                         logger.w(`Icarus cannot load comment "${comment.type}"`);
26 |                         return null;
27 |                     }
28 |                 })()}
29 |             </div>
30 |         </div>;
31 |     }
32 | };
33 | 


--------------------------------------------------------------------------------
/layout/common/donates.jsx:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | const { Component } = require('inferno');
 3 | const view = require('hexo-component-inferno/lib/core/view');
 4 | 
 5 | const logger = createLogger.default();
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { config, helper } = this.props;
10 |         const { __ } = helper;
11 |         const { donates = [] } = config;
12 |         if (!Array.isArray(donates) || !donates.length) {
13 |             return null;
14 |         }
15 |         return <div class="card">
16 |             <div class="card-content">
17 |                 <h3 class="menu-label has-text-centered">{__('donate.title')}</h3>
18 |                 <div class="buttons is-centered">
19 |                     {donates.map(service => {
20 |                         const type = service.type;
21 |                         if (typeof type === 'string') {
22 |                             try {
23 |                                 let Donate = view.require('donate/' + type);
24 |                                 Donate = Donate.Cacheable ? Donate.Cacheable : Donate;
25 |                                 return <Donate helper={helper} donate={service} />;
26 |                             } catch (e) {
27 |                                 logger.w(`Icarus cannot load donate button "${type}"`);
28 |                             }
29 |                         }
30 |                         return null;
31 |                     })}
32 |                 </div>
33 |             </div>
34 |         </div>;
35 |     }
36 | };
37 | 


--------------------------------------------------------------------------------
/layout/common/footer.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
 3 | 
 4 | class Footer extends Component {
 5 |     render() {
 6 |         const {
 7 |             logo,
 8 |             logoUrl,
 9 |             siteUrl,
10 |             siteTitle,
11 |             siteYear,
12 |             author,
13 |             links,
14 |             copyright,
15 |             showVisitorCounter,
16 |             visitorCounterTitle
17 |         } = this.props;
18 | 
19 |         let footerLogo = '';
20 |         if (logo) {
21 |             if (logo.text) {
22 |                 footerLogo = logo.text;
23 |             } else {
24 |                 footerLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
25 |             }
26 |         } else {
27 |             footerLogo = siteTitle;
28 |         }
29 | 
30 |         return <footer class="footer">
31 |             <div class="container">
32 |                 <div class="level">
33 |                     <div class="level-start">
34 |                         <a class="footer-logo is-block mb-2" href={siteUrl}>
35 |                             {footerLogo}
36 |                         </a>
37 |                         <p class="is-size-7">
38 |                             <span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
39 |                             &nbsp;&nbsp;Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>&nbsp;&&nbsp;
40 |                             <a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
41 |                             {showVisitorCounter ? <br /> : null}
42 |                             {showVisitorCounter ? <span id="busuanzi_container_site_uv"
43 |                                 dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
44 |                         </p>
45 |                         {copyright ? <p class="is-size-7" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
46 |                     </div>
47 |                     <div class="level-end">
48 |                         {Object.keys(links).length ? <div class="field has-addons">
49 |                             {Object.keys(links).map(name => {
50 |                                 const link = links[name];
51 |                                 return <p class="control">
52 |                                     <a class={`button is-transparent ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
53 |                                         {link.icon ? <i class={link.icon}></i> : name}
54 |                                     </a>
55 |                                 </p>;
56 |                             })}
57 |                         </div> : null}
58 |                     </div>
59 |                 </div>
60 |             </div>
61 |         </footer>;
62 |     }
63 | }
64 | 
65 | module.exports = cacheComponent(Footer, 'common.footer', props => {
66 |     const { config, helper } = props;
67 |     const { url_for, _p, date } = helper;
68 |     const { logo, title, author, footer, plugins } = config;
69 | 
70 |     const links = {};
71 |     if (footer && footer.links) {
72 |         Object.keys(footer.links).forEach(name => {
73 |             const link = footer.links[name];
74 |             links[name] = {
75 |                 url: url_for(typeof link === 'string' ? link : link.url),
76 |                 icon: link.icon
77 |             };
78 |         });
79 |     }
80 | 
81 |     return {
82 |         logo,
83 |         logoUrl: url_for(logo),
84 |         siteUrl: url_for('/'),
85 |         siteTitle: title,
86 |         siteYear: date(new Date(), 'YYYY'),
87 |         author,
88 |         links,
89 |         copyright: footer?.copyright ?? '',
90 |         showVisitorCounter: plugins && plugins.busuanzi === true,
91 |         visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>')
92 |     };
93 | });
94 | 


--------------------------------------------------------------------------------
/layout/common/head.jsx:
--------------------------------------------------------------------------------
  1 | const { Component } = require('inferno');
  2 | const MetaTags = require('hexo-component-inferno/lib/view/misc/meta');
  3 | const WebApp = require('hexo-component-inferno/lib/view/misc/web_app');
  4 | const OpenGraph = require('hexo-component-inferno/lib/view/misc/open_graph');
  5 | const StructuredData = require('hexo-component-inferno/lib/view/misc/structured_data');
  6 | const Plugins = require('./plugins');
  7 | 
  8 | function getPageTitle(page, siteTitle, helper) {
  9 |     let title = page.title;
 10 | 
 11 |     if (helper.is_archive()) {
 12 |         title = helper._p('common.archive', Infinity);
 13 |         if (helper.is_month()) {
 14 |             title += ': ' + page.year + '/' + page.month;
 15 |         } else if (helper.is_year()) {
 16 |             title += ': ' + page.year;
 17 |         }
 18 |     } else if (helper.is_category()) {
 19 |         title = helper._p('common.category', 1) + ': ' + page.category;
 20 |     } else if (helper.is_tag()) {
 21 |         title = helper._p('common.tag', 1) + ': ' + page.tag;
 22 |     } else if (helper.is_categories()) {
 23 |         title = helper._p('common.category', Infinity);
 24 |     } else if (helper.is_tags()) {
 25 |         title = helper._p('common.tag', Infinity);
 26 |     }
 27 | 
 28 |     return [title, siteTitle].filter(str => typeof str !== 'undefined' && str.trim() !== '').join(' - ');
 29 | }
 30 | 
 31 | module.exports = class extends Component {
 32 |     render() {
 33 |         const { site, config, helper, page } = this.props;
 34 |         const { url_for, cdn, fontcdn, iconcdn, is_post } = helper;
 35 |         const {
 36 |             url,
 37 |             head = {},
 38 |             article,
 39 |             highlight,
 40 |             variant = 'default'
 41 |         } = config;
 42 |         const {
 43 |             meta = [],
 44 |             manifest = {},
 45 |             open_graph = {},
 46 |             structured_data = {},
 47 |             canonical_url = page.permalink,
 48 |             rss,
 49 |             favicon
 50 |         } = head;
 51 | 
 52 |         const noIndex = helper.is_archive() || helper.is_category() || helper.is_tag();
 53 | 
 54 |         const language = page.lang || page.language || config.language;
 55 |         const fontCssUrl = {
 56 |             default: fontcdn('Ubuntu:wght@400;600&family=Source+Code+Pro', 'css2'),
 57 |             cyberpunk: fontcdn('Oxanium:wght@300;400;600&family=Roboto+Mono', 'css2')
 58 |         };
 59 | 
 60 |         let hlTheme, images;
 61 |         if (highlight && highlight.enable === false) {
 62 |             hlTheme = null;
 63 |         } else if (article && article.highlight && article.highlight.theme) {
 64 |             hlTheme = article.highlight.theme;
 65 |         } else {
 66 |             hlTheme = 'atom-one-light';
 67 |         }
 68 | 
 69 |         if (typeof page.og_image === 'string') {
 70 |             images = [page.og_image];
 71 |         } else if (typeof page.cover === 'string') {
 72 |             images = [url_for(page.cover)];
 73 |         } else if (typeof page.thumbnail === 'string') {
 74 |             images = [url_for(page.thumbnail)];
 75 |         } else if (article && typeof article.og_image === 'string') {
 76 |             images = [article.og_image];
 77 |         } else if (page.content && page.content.includes('<img')) {
 78 |             let img;
 79 |             images = [];
 80 |             const imgPattern = /<img [^>]*src=['"]([^'"]+)([^>]*>)/gi;
 81 |             while ((img = imgPattern.exec(page.content)) !== null) {
 82 |                 images.push(img[1]);
 83 |             }
 84 |         } else {
 85 |             images = [url_for('/img/og_image.png')];
 86 |         }
 87 | 
 88 |         let adsenseClientId = null;
 89 |         if (Array.isArray(config.widgets)) {
 90 |             const widget = config.widgets.find(widget => widget.type === 'adsense');
 91 |             if (widget) {
 92 |                 adsenseClientId = widget.client_id;
 93 |             }
 94 |         }
 95 | 
 96 |         let openGraphImages = images;
 97 |         if ((typeof open_graph === 'object' && open_graph !== null)
 98 |             && ((Array.isArray(open_graph.image) && open_graph.image.length > 0) || typeof open_graph.image === 'string')) {
 99 |             openGraphImages = open_graph.image;
100 |         } else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
101 |             openGraphImages = page.photos;
102 |         }
103 | 
104 |         let structuredImages = images;
105 |         if ((typeof structured_data === 'object' && structured_data !== null)
106 |             && ((Array.isArray(structured_data.image) && structured_data.image.length > 0) || typeof structured_data.image === 'string')) {
107 |             structuredImages = structured_data.image;
108 |         } else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
109 |             structuredImages = page.photos;
110 |         }
111 | 
112 |         let followItVerificationCode = null;
113 |         if (Array.isArray(config.widgets)) {
114 |             const widget = config.widgets.find(widget => widget.type === 'followit');
115 |             if (widget) {
116 |                 followItVerificationCode = widget.verification_code;
117 |             }
118 |         }
119 | 
120 |         return <head>
121 |             <meta charset="utf-8" />
122 |             <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
123 |             {noIndex ? <meta name="robots" content="noindex" /> : null}
124 |             {meta && meta.length ? <MetaTags meta={meta} /> : null}
125 | 
126 |             <title>{getPageTitle(page, config.title, helper)}</title>
127 | 
128 |             <WebApp.Cacheable
129 |                 helper={helper}
130 |                 favicon={favicon}
131 |                 icons={manifest.icons}
132 |                 themeColor={manifest.theme_color}
133 |                 name={manifest.name || config.title} />
134 | 
135 |             {typeof open_graph === 'object' && open_graph !== null ? <OpenGraph
136 |                 type={open_graph.type || (is_post(page) ? 'article' : 'website')}
137 |                 title={open_graph.title || page.title || config.title}
138 |                 date={page.date}
139 |                 updated={page.updated}
140 |                 author={open_graph.author || config.author}
141 |                 description={open_graph.description || page.description || page.excerpt || page.content || config.description}
142 |                 keywords={(page.tags && page.tags.length ? page.tags : undefined) || config.keywords}
143 |                 url={open_graph.url || page.permalink || url}
144 |                 images={openGraphImages}
145 |                 siteName={open_graph.site_name || config.title}
146 |                 language={language}
147 |                 twitterId={open_graph.twitter_id}
148 |                 twitterCard={open_graph.twitter_card}
149 |                 twitterSite={open_graph.twitter_site}
150 |                 googlePlus={open_graph.google_plus}
151 |                 facebookAdmins={open_graph.fb_admins}
152 |                 facebookAppId={open_graph.fb_app_id} /> : null}
153 | 
154 |             {typeof structured_data === 'object' && structured_data !== null ? <StructuredData
155 |                 title={structured_data.title || page.title || config.title}
156 |                 description={structured_data.description || page.description || page.excerpt || page.content || config.description}
157 |                 url={structured_data.url || page.permalink || url}
158 |                 author={structured_data.author || config.author}
159 |                 publisher={structured_data.publisher || config.title}
160 |                 publisherLogo={structured_data.publisher_logo || config.logo}
161 |                 date={page.date}
162 |                 updated={page.updated}
163 |                 images={structuredImages} /> : null}
164 | 
165 |             {canonical_url ? <link rel="canonical" href={canonical_url} /> : null}
166 |             {rss ? <link rel="alternate" href={url_for(rss)} title={config.title} type="application/atom+xml" /> : null}
167 |             {favicon ? <link rel="icon" href={url_for(favicon)} /> : null}
168 |             <link rel="stylesheet" href={iconcdn()} />
169 |             {hlTheme ? <link data-pjax rel="stylesheet" href={cdn('highlight.js', '11.7.0', 'styles/' + hlTheme + '.css')} /> : null}
170 |             <link rel="stylesheet" href={fontCssUrl[variant]} />
171 |             <link data-pjax rel="stylesheet" href={url_for('/css/' + variant + '.css')} />
172 |             <Plugins site={site} config={config} helper={helper} page={page} head={true} />
173 | 
174 |             {adsenseClientId ? <script data-ad-client={adsenseClientId}
175 |                 src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async></script> : null}
176 | 
177 |             {followItVerificationCode ? <meta name="follow.it-verification-code" content={followItVerificationCode} /> : null}
178 |         </head>;
179 |     }
180 | };
181 | 


--------------------------------------------------------------------------------
/layout/common/navbar.jsx:
--------------------------------------------------------------------------------
  1 | const { Component, Fragment } = require('inferno');
  2 | const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
  3 | const classname = require('hexo-component-inferno/lib/util/classname');
  4 | 
  5 | function isSameLink(a, b) {
  6 |     function santize(url) {
  7 |         let paths = url.replace(/(^\w+:|^)\/\//, '').split('#')[0].split('/').filter(p => p.trim() !== '');
  8 |         if (paths.length > 0 && paths[paths.length - 1].trim() === 'index.html') {
  9 |             paths = paths.slice(0, paths.length - 1);
 10 |         }
 11 |         return paths.join('/');
 12 |     }
 13 |     return santize(a) === santize(b);
 14 | }
 15 | 
 16 | class Navbar extends Component {
 17 |     render() {
 18 |         const {
 19 |             logo,
 20 |             logoUrl,
 21 |             siteUrl,
 22 |             siteTitle,
 23 |             menu,
 24 |             links,
 25 |             showToc,
 26 |             tocTitle,
 27 |             showSearch,
 28 |             searchTitle
 29 |         } = this.props;
 30 | 
 31 |         let navbarLogo = '';
 32 |         if (logo) {
 33 |             if (logo.text) {
 34 |                 navbarLogo = logo.text;
 35 |             } else {
 36 |                 navbarLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
 37 |             }
 38 |         } else {
 39 |             navbarLogo = siteTitle;
 40 |         }
 41 | 
 42 |         return <nav class="navbar navbar-main">
 43 |             <div class="container navbar-container">
 44 |                 <div class="navbar-brand justify-content-center">
 45 |                     <a class="navbar-item navbar-logo" href={siteUrl}>
 46 |                         {navbarLogo}
 47 |                     </a>
 48 |                 </div>
 49 |                 <div class="navbar-menu">
 50 |                     {Object.keys(menu).length ? <div class="navbar-start">
 51 |                         {Object.keys(menu).map(name => {
 52 |                             const item = menu[name];
 53 |                             return <a class={classname({ 'navbar-item': true, 'is-active': item.active })} href={item.url}>{name}</a>;
 54 |                         })}
 55 |                     </div> : null}
 56 |                     <div class="navbar-end">
 57 |                         {Object.keys(links).length ? <Fragment>
 58 |                             {Object.keys(links).map(name => {
 59 |                                 const link = links[name];
 60 |                                 return <a class="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
 61 |                                     {link.icon ? <i class={link.icon}></i> : name}
 62 |                                 </a>;
 63 |                             })}
 64 |                         </Fragment> : null}
 65 |                         {showToc ? <a class="navbar-item is-hidden-tablet catalogue" title={tocTitle} href="javascript:;">
 66 |                             <i class="fas fa-list-ul"></i>
 67 |                         </a> : null}
 68 |                         {showSearch ? <a class="navbar-item search" title={searchTitle} href="javascript:;">
 69 |                             <i class="fas fa-search"></i>
 70 |                         </a> : null}
 71 |                     </div>
 72 |                 </div>
 73 |             </div>
 74 |         </nav>;
 75 |     }
 76 | }
 77 | 
 78 | module.exports = cacheComponent(Navbar, 'common.navbar', props => {
 79 |     const { config, helper, page } = props;
 80 |     const { url_for, _p, __ } = helper;
 81 |     const { logo, title, navbar, widgets, search } = config;
 82 | 
 83 |     const hasTocWidget = Array.isArray(widgets) && widgets.find(widget => widget.type === 'toc');
 84 |     const showToc = (config.toc === true || page.toc) && hasTocWidget && ['page', 'post'].includes(page.layout);
 85 | 
 86 |     const menu = {};
 87 |     if (navbar && navbar.menu) {
 88 |         const pageUrl = typeof page.path !== 'undefined' ? url_for(page.path) : '';
 89 |         Object.keys(navbar.menu).forEach(name => {
 90 |             const url = url_for(navbar.menu[name]);
 91 |             const active = isSameLink(url, pageUrl);
 92 |             menu[name] = { url, active };
 93 |         });
 94 |     }
 95 | 
 96 |     const links = {};
 97 |     if (navbar && navbar.links) {
 98 |         Object.keys(navbar.links).forEach(name => {
 99 |             const link = navbar.links[name];
100 |             links[name] = {
101 |                 url: url_for(typeof link === 'string' ? link : link.url),
102 |                 icon: link.icon
103 |             };
104 |         });
105 |     }
106 | 
107 |     return {
108 |         logo,
109 |         logoUrl: url_for(logo),
110 |         siteUrl: url_for('/'),
111 |         siteTitle: title,
112 |         menu,
113 |         links,
114 |         showToc,
115 |         tocTitle: _p('widget.catalogue', Infinity),
116 |         showSearch: search && search.type,
117 |         searchTitle: __('search.search')
118 |     };
119 | });
120 | 


--------------------------------------------------------------------------------
/layout/common/plugins.jsx:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | const { Component, Fragment } = require('inferno');
 3 | const view = require('hexo-component-inferno/lib/core/view');
 4 | 
 5 | const logger = createLogger.default();
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { site, config, page, helper, head } = this.props;
10 |         const { plugins = [] } = config;
11 | 
12 |         return <Fragment>
13 |             {Object.keys(plugins).map(name => {
14 |                 // plugin is not enabled
15 |                 if (!plugins[name]) {
16 |                     return null;
17 |                 }
18 |                 try {
19 |                     let Plugin = view.require('plugin/' + name);
20 |                     Plugin = Plugin.Cacheable ? Plugin.Cacheable : Plugin;
21 |                     return <Plugin site={site} config={config} page={page} helper={helper} plugin={plugins[name]} head={head} />;
22 |                 } catch (e) {
23 |                     logger.w(`Icarus cannot load plugin "${name}"`);
24 |                     return null;
25 |                 }
26 |             })}
27 |         </Fragment>;
28 |     }
29 | };
30 | 


--------------------------------------------------------------------------------
/layout/common/scripts.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
 3 | const Plugins = require('./plugins');
 4 | 
 5 | module.exports = class extends Component {
 6 |     render() {
 7 |         const { site, config, helper, page } = this.props;
 8 |         const { url_for, cdn } = helper;
 9 |         const { article } = config;
10 |         const language = toMomentLocale(page.lang || page.language || config.language || 'en');
11 | 
12 |         let fold = 'unfolded';
13 |         let clipboard = true;
14 |         if (article && article.highlight) {
15 |             if (typeof article.highlight.clipboard !== 'undefined') {
16 |                 clipboard = !!article.highlight.clipboard;
17 |             }
18 |             if (typeof article.highlight.fold === 'string') {
19 |                 fold = article.highlight.fold;
20 |             }
21 |         }
22 | 
23 |         const embeddedConfig = `var IcarusThemeSettings = {
24 |             article: {
25 |                 highlight: {
26 |                     clipboard: ${clipboard},
27 |                     fold: '${fold}'
28 |                 }
29 |             }
30 |         };`;
31 | 
32 |         return <Fragment>
33 |             <script src={cdn('jquery', '3.3.1', 'dist/jquery.min.js')}></script>
34 |             <script src={cdn('moment', '2.22.2', 'min/moment-with-locales.min.js')}></script>
35 |             {clipboard && <script src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')} defer></script>}
36 |             <script dangerouslySetInnerHTML={{ __html: `moment.locale("${language}");` }}></script>
37 |             <script dangerouslySetInnerHTML={{ __html: embeddedConfig }}></script>
38 |             <script data-pjax src={url_for('/js/column.js')}></script>
39 |             <Plugins site={site} config={config} page={page} helper={helper} head={false} />
40 |             <script data-pjax src={url_for('/js/main.js')} defer></script>
41 |         </Fragment>;
42 |     }
43 | };
44 | 


--------------------------------------------------------------------------------
/layout/common/search.jsx:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | const { Component } = require('inferno');
 3 | const view = require('hexo-component-inferno/lib/core/view');
 4 | 
 5 | const logger = createLogger.default();
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { config, helper } = this.props;
10 |         const { search } = config;
11 |         if (!search || typeof search.type !== 'string') {
12 |             return null;
13 |         }
14 | 
15 |         try {
16 |             let Search = view.require('search/' + search.type);
17 |             Search = Search.Cacheable ? Search.Cacheable : Search;
18 |             return <Search config={config} helper={helper} search={search} />;
19 |         } catch (e) {
20 |             logger.w(`Icarus cannot load search "${search.type}"`);
21 |             return null;
22 |         }
23 |     }
24 | };
25 | 


--------------------------------------------------------------------------------
/layout/common/share.jsx:
--------------------------------------------------------------------------------
 1 | const createLogger = require('hexo-log');
 2 | const { Component } = require('inferno');
 3 | const view = require('hexo-component-inferno/lib/core/view');
 4 | 
 5 | const logger = createLogger.default();
 6 | 
 7 | module.exports = class extends Component {
 8 |     render() {
 9 |         const { config, page, helper } = this.props;
10 |         const { share } = config;
11 |         if (!share || typeof share.type !== 'string') {
12 |             return null;
13 |         }
14 | 
15 |         try {
16 |             let Share = view.require('share/' + share.type);
17 |             Share = Share.Cacheable ? Share.Cacheable : Share;
18 |             return <Share config={config} page={page} helper={helper} share={share} />;
19 |         } catch (e) {
20 |             logger.w(`Icarus cannot load share button "${share.type}"`);
21 |             return null;
22 |         }
23 |     }
24 | };
25 | 


--------------------------------------------------------------------------------
/layout/common/widgets.jsx:
--------------------------------------------------------------------------------
  1 | const createLogger = require('hexo-log');
  2 | const { Component } = require('inferno');
  3 | const view = require('hexo-component-inferno/lib/core/view');
  4 | const classname = require('hexo-component-inferno/lib/util/classname');
  5 | 
  6 | const logger = createLogger.default();
  7 | 
  8 | function formatWidgets(widgets) {
  9 |     const result = {};
 10 |     if (Array.isArray(widgets)) {
 11 |         widgets.filter(widget => typeof widget === 'object').forEach(widget => {
 12 |             if ('position' in widget && (widget.position === 'left' || widget.position === 'right')) {
 13 |                 if (!(widget.position in result)) {
 14 |                     result[widget.position] = [widget];
 15 |                 } else {
 16 |                     result[widget.position].push(widget);
 17 |                 }
 18 |             }
 19 |         });
 20 |     }
 21 |     return result;
 22 | }
 23 | 
 24 | function hasColumn(widgets, position, config, page) {
 25 |     const showToc = (config.toc === true) && ['page', 'post'].includes(page.layout);
 26 |     if (Array.isArray(widgets)) {
 27 |         return typeof widgets.find(widget => {
 28 |             if (widget.type === 'toc' && !showToc) {
 29 |                 return false;
 30 |             }
 31 |             return widget.position === position;
 32 |         }) !== 'undefined';
 33 |     }
 34 |     return false;
 35 | }
 36 | 
 37 | function getColumnCount(widgets, config, page) {
 38 |     return [hasColumn(widgets, 'left', config, page), hasColumn(widgets, 'right', config, page)].filter(v => !!v).length + 1;
 39 | }
 40 | 
 41 | function getColumnSizeClass(columnCount) {
 42 |     switch (columnCount) {
 43 |         case 2:
 44 |             return 'is-4-tablet is-4-desktop is-4-widescreen';
 45 |         case 3:
 46 |             return 'is-4-tablet is-4-desktop is-3-widescreen';
 47 |     }
 48 |     return '';
 49 | }
 50 | 
 51 | function getColumnVisibilityClass(columnCount, position) {
 52 |     if (columnCount === 3 && position === 'right') {
 53 |         return 'is-hidden-touch is-hidden-desktop-only';
 54 |     }
 55 |     return '';
 56 | }
 57 | 
 58 | function getColumnOrderClass(position) {
 59 |     return position === 'left' ? 'order-1' : 'order-3';
 60 | }
 61 | 
 62 | function isColumnSticky(config, position) {
 63 |     return typeof config.sidebar === 'object'
 64 |         && position in config.sidebar
 65 |         && config.sidebar[position].sticky === true;
 66 | }
 67 | 
 68 | class Widgets extends Component {
 69 |     render() {
 70 |         const { site, config, helper, page, position } = this.props;
 71 |         const widgets = formatWidgets(config.widgets)[position] || [];
 72 |         const columnCount = getColumnCount(config.widgets, config, page);
 73 | 
 74 |         if (!widgets.length) {
 75 |             return null;
 76 |         }
 77 | 
 78 |         return <div class={classname({
 79 |             'column': true,
 80 |             ['column-' + position]: true,
 81 |             [getColumnSizeClass(columnCount)]: true,
 82 |             [getColumnVisibilityClass(columnCount, position)]: true,
 83 |             [getColumnOrderClass(position)]: true,
 84 |             'is-sticky': isColumnSticky(config, position)
 85 |         })}>
 86 |             {widgets.map(widget => {
 87 |                 // widget type is not defined
 88 |                 if (!widget.type) {
 89 |                     return null;
 90 |                 }
 91 |                 try {
 92 |                     let Widget = view.require('widget/' + widget.type);
 93 |                     Widget = Widget.Cacheable ? Widget.Cacheable : Widget;
 94 |                     return <Widget site={site} helper={helper} config={config} page={page} widget={widget} />;
 95 |                 } catch (e) {
 96 |                     logger.w(`Icarus cannot load widget "${widget.type}"`);
 97 |                 }
 98 |                 return null;
 99 |             })}
100 |             {position === 'left' && hasColumn(config.widgets, 'right', config, page) ? <div class={classname({
101 |                 'column-right-shadow': true,
102 |                 'is-hidden-widescreen': true,
103 |                 'is-sticky': isColumnSticky(config, 'right')
104 |             })}></div> : null}
105 |         </div>;
106 |     }
107 | }
108 | 
109 | Widgets.getColumnCount = getColumnCount;
110 | 
111 | module.exports = Widgets;
112 | 


--------------------------------------------------------------------------------
/layout/donate/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/layout/donate/.gitkeep


--------------------------------------------------------------------------------
/layout/index.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
 3 | const Article = require('./common/article');
 4 | 
 5 | module.exports = class extends Component {
 6 |     render() {
 7 |         const { config, page, helper } = this.props;
 8 |         const { __, url_for } = helper;
 9 | 
10 |         return <Fragment>
11 |             {page.posts.map(post => <Article config={config} page={post} helper={helper} index={true} />)}
12 |             {page.total > 1 ? <Paginator
13 |                 current={page.current}
14 |                 total={page.total}
15 |                 baseUrl={page.base}
16 |                 path={config.pagination_dir}
17 |                 urlFor={url_for}
18 |                 prevTitle={__('common.prev')}
19 |                 nextTitle={__('common.next')} /> : null}
20 |         </Fragment>;
21 |     }
22 | };
23 | 


--------------------------------------------------------------------------------
/layout/layout.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const classname = require('hexo-component-inferno/lib/util/classname');
 3 | const Head = require('./common/head');
 4 | const Navbar = require('./common/navbar');
 5 | const Widgets = require('./common/widgets');
 6 | const Footer = require('./common/footer');
 7 | const Scripts = require('./common/scripts');
 8 | const Search = require('./common/search');
 9 | 
10 | module.exports = class extends Component {
11 |     render() {
12 |         const { site, config, page, helper, body } = this.props;
13 | 
14 |         const language = page.lang || page.language || config.language;
15 |         const columnCount = Widgets.getColumnCount(config.widgets, config, page);
16 | 
17 |         return <html lang={language ? language.substr(0, 2) : ''}>
18 |             <Head site={site} config={config} helper={helper} page={page} />
19 |             <body class={`is-${columnCount}-column`}>
20 |                 <Navbar config={config} helper={helper} page={page} />
21 |                 <section class="section">
22 |                     <div class="container">
23 |                         <div class="columns">
24 |                             <div class={classname({
25 |                                 column: true,
26 |                                 'order-2': true,
27 |                                 'column-main': true,
28 |                                 'is-12': columnCount === 1,
29 |                                 'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
30 |                                 'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3
31 |                             })} dangerouslySetInnerHTML={{ __html: body }}></div>
32 |                             <Widgets site={site} config={config} helper={helper} page={page} position={'left'} />
33 |                             <Widgets site={site} config={config} helper={helper} page={page} position={'right'} />
34 |                         </div>
35 |                     </div>
36 |                 </section>
37 |                 <Footer config={config} helper={helper} />
38 |                 <Scripts site={site} config={config} helper={helper} page={page} />
39 |                 <Search config={config} helper={helper} />
40 |             </body>
41 |         </html>;
42 |     }
43 | };
44 | 


--------------------------------------------------------------------------------
/layout/misc/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/layout/misc/.gitkeep


--------------------------------------------------------------------------------
/layout/page.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const Article = require('./common/article');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { config, page, helper } = this.props;
 7 | 
 8 |         return <Article config={config} page={page} helper={helper} index={false} />;
 9 |     }
10 | };
11 | 


--------------------------------------------------------------------------------
/layout/plugin/animejs.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
 3 | 
 4 | class AnimeJs extends Component {
 5 |     render() {
 6 |         if (this.props.head) {
 7 |             return <style dangerouslySetInnerHTML={{ __html: 'body>.footer,body>.navbar,body>.section{opacity:0}' }}></style>;
 8 |         }
 9 |         return <script src={this.props.jsUrl}></script>;
10 | 
11 |     }
12 | }
13 | 
14 | AnimeJs.Cacheable = cacheComponent(AnimeJs, 'plugin.animejs', props => {
15 |     const { helper, head } = props;
16 |     return {
17 |         head,
18 |         jsUrl: helper.url_for('/js/animation.js')
19 |     };
20 | });
21 | 
22 | module.exports = AnimeJs;
23 | 


--------------------------------------------------------------------------------
/layout/plugin/back_to_top.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
 3 | 
 4 | class BackToTop extends Component {
 5 |     render() {
 6 |         const { title, jsUrl } = this.props;
 7 | 
 8 |         return <Fragment>
 9 |             <a id="back-to-top" title={title} href="javascript:;">
10 |                 <i class="fas fa-chevron-up"></i>
11 |             </a>
12 |             <script data-pjax src={jsUrl} defer></script>
13 |         </Fragment>;
14 | 
15 |     }
16 | }
17 | 
18 | BackToTop.Cacheable = cacheComponent(BackToTop, 'plugin.backtotop', props => {
19 |     const { helper, head } = props;
20 |     if (head) {
21 |         return null;
22 |     }
23 |     return {
24 |         title: helper.__('plugin.backtotop'),
25 |         jsUrl: helper.url_for('/js/back_to_top.js')
26 |     };
27 | });
28 | 
29 | module.exports = BackToTop;
30 | 


--------------------------------------------------------------------------------
/layout/plugin/pjax.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | 
 3 | class Pjax extends Component {
 4 |     render() {
 5 |         if (this.props.head) {
 6 |             return null;
 7 |         }
 8 |         const { helper } = this.props;
 9 |         const { url_for, cdn } = helper;
10 | 
11 |         return <Fragment>
12 |             <script src={cdn('pjax', '0.2.8', 'pjax.min.js')}></script>
13 |             <script src={url_for('/js/pjax.js')}></script>
14 |         </Fragment>;
15 |     }
16 | }
17 | 
18 | module.exports = Pjax;
19 | 


--------------------------------------------------------------------------------
/layout/post.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const Article = require('./common/article');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { config, page, helper } = this.props;
 7 | 
 8 |         return <Article config={config} page={page} helper={helper} index={false} />;
 9 |     }
10 | };
11 | 


--------------------------------------------------------------------------------
/layout/search/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/layout/search/.gitkeep


--------------------------------------------------------------------------------
/layout/share/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/layout/share/.gitkeep


--------------------------------------------------------------------------------
/layout/tag.jsx:
--------------------------------------------------------------------------------
 1 | const { Component, Fragment } = require('inferno');
 2 | const Index = require('./index');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { config, page, helper } = this.props;
 7 |         const { url_for, _p } = helper;
 8 | 
 9 |         return <Fragment>
10 |             <div class="card">
11 |                 <div class="card-content">
12 |                     <nav class="breadcrumb" aria-label="breadcrumbs">
13 |                         <ul>
14 |                             <li><a href={url_for('/tags/')}>{_p('common.tag', Infinity)}</a></li>
15 |                             <li class="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
16 |                         </ul>
17 |                     </nav>
18 |                 </div>
19 |             </div>
20 |             <Index config={config} page={page} helper={helper} />
21 |         </Fragment>;
22 |     }
23 | };
24 | 


--------------------------------------------------------------------------------
/layout/tags.jsx:
--------------------------------------------------------------------------------
 1 | const { Component } = require('inferno');
 2 | const Tags = require('hexo-component-inferno/lib/view/widget/tags');
 3 | 
 4 | module.exports = class extends Component {
 5 |     render() {
 6 |         const { site, helper } = this.props;
 7 | 
 8 |         return <Tags.Cacheable site={site} helper={helper} />;
 9 |     }
10 | };
11 | 


--------------------------------------------------------------------------------
/layout/widget/profile.jsx:
--------------------------------------------------------------------------------
  1 | const { Component } = require('inferno');
  2 | const gravatrHelper = require('hexo-util').gravatar;
  3 | const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
  4 | 
  5 | class Profile extends Component {
  6 |     renderSocialLinks(links) {
  7 |         if (!links.length) {
  8 |             return null;
  9 |         }
 10 |         return <div class="level is-mobile is-multiline">
 11 |             {links.filter(link => typeof link === 'object').map(link => {
 12 |                 return <a class="level-item button is-transparent is-marginless"
 13 |                     target="_blank" rel="me noopener" title={link.name} href={link.url}>
 14 |                     {'icon' in link ? <i class={link.icon}></i> : link.name}
 15 |                 </a>;
 16 |             })}
 17 |         </div>;
 18 |     }
 19 | 
 20 |     render() {
 21 |         const {
 22 |             avatar,
 23 |             avatarRounded,
 24 |             author,
 25 |             authorTitle,
 26 |             location,
 27 |             counter,
 28 |             followLink,
 29 |             followTitle,
 30 |             socialLinks
 31 |         } = this.props;
 32 |         return <div class="card widget" data-type="profile">
 33 |             <div class="card-content">
 34 |                 <nav class="level">
 35 |                     <div class="level-item has-text-centered flex-shrink-1">
 36 |                         <div>
 37 |                             <figure class="image is-128x128 mx-auto mb-2">
 38 |                                 <img class={'avatar' + (avatarRounded ? ' is-rounded' : '')} src={avatar} alt={author} />
 39 |                             </figure>
 40 |                             {author ? <p class="title is-size-4 is-block" style={{'line-height': 'inherit'}}>{author}</p> : null}
 41 |                             {authorTitle ? <p class="is-size-6 is-block">{authorTitle}</p> : null}
 42 |                             {location ? <p class="is-size-6 is-flex justify-content-center">
 43 |                                 <i class="fas fa-map-marker-alt mr-1"></i>
 44 |                                 <span>{location}</span>
 45 |                             </p> : null}
 46 |                         </div>
 47 |                     </div>
 48 |                 </nav>
 49 |                 <nav class="level is-mobile">
 50 |                     <div class="level-item has-text-centered is-marginless">
 51 |                         <div>
 52 |                             <p class="heading">{counter.post.title}</p>
 53 |                             <a href={counter.post.url}>
 54 |                                 <p class="title">{counter.post.count}</p>
 55 |                             </a>
 56 |                         </div>
 57 |                     </div>
 58 |                     <div class="level-item has-text-centered is-marginless">
 59 |                         <div>
 60 |                             <p class="heading">{counter.category.title}</p>
 61 |                             <a href={counter.category.url}>
 62 |                                 <p class="title">{counter.category.count}</p>
 63 |                             </a>
 64 |                         </div>
 65 |                     </div>
 66 |                     <div class="level-item has-text-centered is-marginless">
 67 |                         <div>
 68 |                             <p class="heading">{counter.tag.title}</p>
 69 |                             <a href={counter.tag.url}>
 70 |                                 <p class="title">{counter.tag.count}</p>
 71 |                             </a>
 72 |                         </div>
 73 |                     </div>
 74 |                 </nav>
 75 |                 {followLink ? <div class="level">
 76 |                     <a class="level-item button is-primary is-rounded" href={followLink} target="_blank" rel="me noopener">{followTitle}</a>
 77 |                 </div> : null}
 78 |                 {socialLinks ? this.renderSocialLinks(socialLinks) : null}
 79 |             </div>
 80 |         </div>;
 81 |     }
 82 | }
 83 | 
 84 | Profile.Cacheable = cacheComponent(Profile, 'widget.profile', props => {
 85 |     const { site, helper, widget } = props;
 86 |     const {
 87 |         avatar,
 88 |         gravatar,
 89 |         avatar_rounded = false,
 90 |         author = props.config.author,
 91 |         author_title,
 92 |         location,
 93 |         follow_link,
 94 |         social_links
 95 |     } = widget;
 96 |     const { url_for, _p, __ } = helper;
 97 | 
 98 |     function getAvatar() {
 99 |         if (gravatar) {
100 |             return gravatrHelper(gravatar, 128);
101 |         }
102 |         if (avatar) {
103 |             return url_for(avatar);
104 |         }
105 |         return url_for('/img/avatar.png');
106 |     }
107 | 
108 |     const postCount = site.posts.length;
109 |     const categoryCount = site.categories.filter(category => category.length).length;
110 |     const tagCount = site.tags.filter(tag => tag.length).length;
111 | 
112 |     const socialLinks = social_links ? Object.keys(social_links).map(name => {
113 |         const link = social_links[name];
114 |         if (typeof link === 'string') {
115 |             return {
116 |                 name,
117 |                 url: url_for(link)
118 |             };
119 |         }
120 |         return {
121 |             name,
122 |             url: url_for(link.url),
123 |             icon: link.icon
124 |         };
125 |     }) : null;
126 | 
127 |     return {
128 |         avatar: getAvatar(),
129 |         avatarRounded: avatar_rounded,
130 |         author,
131 |         authorTitle: author_title,
132 |         location,
133 |         counter: {
134 |             post: {
135 |                 count: postCount,
136 |                 title: _p('common.post', postCount),
137 |                 url: url_for('/archives/')
138 |             },
139 |             category: {
140 |                 count: categoryCount,
141 |                 title: _p('common.category', categoryCount),
142 |                 url: url_for('/categories/')
143 |             },
144 |             tag: {
145 |                 count: tagCount,
146 |                 title: _p('common.tag', tagCount),
147 |                 url: url_for('/tags/')
148 |             }
149 |         },
150 |         followLink: follow_link ? url_for(follow_link) : undefined,
151 |         followTitle: __('widget.follow'),
152 |         socialLinks
153 |     };
154 | });
155 | 
156 | module.exports = Profile;
157 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "hexo-theme-icarus",
 3 |   "version": "6.1.1",
 4 |   "author": "ppoffice <ppoffice@users.noreply.github.com>",
 5 |   "license": "MIT",
 6 |   "description": "A simple, delicate, and modern theme for Hexo",
 7 |   "keywords": [
 8 |     "hexo",
 9 |     "theme",
10 |     "icarus"
11 |   ],
12 |   "homepage": "https://github.com/ppoffice/hexo-theme-icarus",
13 |   "repository": "https://github.com/ppoffice/hexo-theme-icarus.git",
14 |   "bugs": {
15 |     "url": "https://github.com/ppoffice/hexo-theme-icarus/issues"
16 |   },
17 |   "engines": {
18 |     "node": ">=14"
19 |   },
20 |   "scripts": {
21 |     "lint": "eslint --ext .js --ext .jsx --ext .json ."
22 |   },
23 |   "devDependencies": {
24 |     "eslint": "^8.56.0",
25 |     "eslint-config-hexo": "^5.0.0",
26 |     "eslint-plugin-json": "^3.1.0",
27 |     "eslint-plugin-react": "^7.33.2"
28 |   },
29 |   "dependencies": {
30 |     "bulma-stylus": "0.8.0",
31 |     "deepmerge": "^4.3.1",
32 |     "hexo": "^7.1.1",
33 |     "hexo-component-inferno": "^3.1.2",
34 |     "hexo-log": "^4.1.0",
35 |     "hexo-pagination": "^3.0.0",
36 |     "hexo-renderer-inferno": "^1.0.2",
37 |     "hexo-renderer-stylus": "^3.0.1",
38 |     "hexo-util": "^3.2.0",
39 |     "inferno": "^8.2.3",
40 |     "inferno-create-element": "^8.2.3",
41 |     "moment": "^2.30.1",
42 |     "semver": "^7.5.4"
43 |   }
44 | }
45 | 


--------------------------------------------------------------------------------
/scripts/index.js:
--------------------------------------------------------------------------------
 1 | /* global hexo */
 2 | const createLogger = require('hexo-log');
 3 | 
 4 | const logger = createLogger.default();
 5 | 
 6 | /**
 7 |  * Print welcome message
 8 |  */
 9 | logger.info(`=======================================
10 |  ██╗ ██████╗ █████╗ ██████╗ ██╗   ██╗███████╗
11 |  ██║██╔════╝██╔══██╗██╔══██╗██║   ██║██╔════╝
12 |  ██║██║     ███████║██████╔╝██║   ██║███████╗
13 |  ██║██║     ██╔══██║██╔══██╗██║   ██║╚════██║
14 |  ██║╚██████╗██║  ██║██║  ██║╚██████╔╝███████║
15 |  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝
16 | =============================================`);
17 | 
18 | /**
19 |  * Check if all dependencies are installed
20 |  */
21 | require('../include/dependency')(hexo);
22 | 
23 | /**
24 |  * Configuration file checking and migration
25 |  */
26 | require('../include/config')(hexo);
27 | 
28 | /**
29 |  * Register Hexo extensions and remove Hexo filters that could cause OOM
30 |  */
31 | require('../include/register')(hexo);
32 | 


--------------------------------------------------------------------------------
/source/css/default.styl:
--------------------------------------------------------------------------------
1 | @import 'style'
2 | 


--------------------------------------------------------------------------------
/source/css/style.styl:
--------------------------------------------------------------------------------
 1 | // Base CSS framework
 2 | @import '../../include/style/base'
 3 | // Helper classes & mixins
 4 | @import '../../include/style/helper'
 5 | // Icarus components
 6 | @import '../../include/style/button'
 7 | @import '../../include/style/card'
 8 | @import '../../include/style/article'
 9 | @import '../../include/style/navbar'
10 | @import '../../include/style/footer'
11 | @import '../../include/style/pagination'
12 | @import '../../include/style/timeline'
13 | @import '../../include/style/search'
14 | @import '../../include/style/codeblock'
15 | @import '../../include/style/widget'
16 | @import '../../include/style/donate'
17 | @import '../../include/style/plugin'
18 | @import '../../include/style/responsive'
19 | 


--------------------------------------------------------------------------------
/source/img/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/source/img/avatar.png


--------------------------------------------------------------------------------
/source/img/favicon.svg:
--------------------------------------------------------------------------------
1 | <svg
2 |     xmlns="http://www.w3.org/2000/svg" version="1.1" width="256" height="256" viewbox="0 0 949 256">
3 |     <path fill="#2366d1" d="M110.85125168440814 128L221.70250336881628 192L110.85125168440814 256L0 192Z"/>
4 |     <path fill="#609dff" d="M110.85125168440814 64L221.70250336881628 128L110.85125168440814 192L0 128Z"/>
5 |     <path fill="#a4c7ff" d="M110.85125168440814 0L221.70250336881628 64L110.85125168440814 128L0 64Z"/>
6 | </svg>


--------------------------------------------------------------------------------
/source/img/og_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ppoffice/hexo-theme-icarus/76d8cd0197003fc1ad673741d66a803ebb116f81/source/img/og_image.png


--------------------------------------------------------------------------------
/source/img/razor-bottom-black.svg:
--------------------------------------------------------------------------------
1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920px" height="39px">
2 | <path fill-rule="evenodd" fill="rgb(0, 0, 0)" d="M1877.759,23.791 L1874.461,20.504 L1879.969,15.027 L1868.965,15.027 L1874.461,20.504 L1871.156,23.791 L1789.442,23.791 L1784.749,28.484 L1775.502,37.704 L1769.337,31.559 L1738.089,31.695 L1733.080,31.695 L1720.422,19.079 L1686.790,19.079 L1679.552,26.293 L1386.290,26.255 L1380.520,20.508 L1371.871,29.132 L1368.980,26.255 L1203.819,26.293 L1191.058,38.996 L1167.007,15.027 L1167.000,15.038 L1166.989,15.027 L1157.936,24.049 L1154.094,24.049 L1151.994,21.956 L1155.330,18.643 L1148.674,18.643 L1151.994,21.956 L1149.933,24.007 L1072.000,24.040 L1072.000,24.049 L1061.000,24.044 L1050.000,24.049 L1050.000,24.040 L972.067,24.007 L970.005,21.956 L973.326,18.643 L966.670,18.643 L970.005,21.956 L967.906,24.049 L964.064,24.049 L955.012,15.027 L955.000,15.038 L954.993,15.027 L930.942,38.996 L918.181,26.293 L818.020,26.255 L815.129,29.132 L806.480,20.508 L800.710,26.255 L661.448,26.293 L654.209,19.079 L620.578,19.079 L607.919,31.695 L602.910,31.695 L571.663,31.559 L565.497,37.704 L556.251,28.484 L551.557,23.791 L469.844,23.791 L466.539,20.504 L472.035,15.027 L461.031,15.027 L466.539,20.504 L463.241,23.791 L204.638,23.791 L195.467,15.027 L195.449,15.049 L195.426,15.027 L179.458,31.695 L166.537,31.695 L158.884,24.049 L0.001,24.049 L0.001,-0.012 L1919.998,-0.012 L1919.998,24.049 L1877.759,23.791 ZM228.624,15.027 L226.889,15.027 L226.889,20.205 L228.624,20.205 L228.624,15.027 ZM231.248,15.027 L229.518,15.027 L229.518,20.205 L231.248,20.205 L231.248,15.027 ZM243.370,15.027 L241.640,15.027 L241.640,20.205 L243.370,20.205 L243.370,15.027 ZM264.168,15.027 L258.973,15.027 L258.973,20.205 L264.168,20.205 L264.168,15.027 ZM584.675,24.989 L582.941,24.989 L582.941,26.714 L584.675,26.714 L584.675,24.989 ZM591.316,21.536 L589.582,21.536 L589.582,26.714 L591.316,26.714 L591.316,21.536 ZM604.751,21.536 L603.017,21.536 L603.017,23.260 L604.751,23.260 L604.751,21.536 ZM604.751,24.989 L603.017,24.989 L603.017,26.714 L604.751,26.714 L604.751,24.989 ZM1737.983,21.536 L1736.249,21.536 L1736.249,23.260 L1737.983,23.260 L1737.983,21.536 ZM1737.983,24.989 L1736.249,24.989 L1736.249,26.714 L1737.983,26.714 L1737.983,24.989 ZM1751.418,21.536 L1749.683,21.536 L1749.683,26.714 L1751.418,26.714 L1751.418,21.536 ZM1758.059,24.989 L1756.324,24.989 L1756.324,26.714 L1758.059,26.714 L1758.059,24.989 ZM1877.785,23.818 L1871.129,23.818 L1871.156,23.791 L1877.759,23.791 L1877.785,23.818 ZM1367.778,33.211 L1371.871,29.132 L1375.975,33.211 L1367.778,33.211 ZM469.871,23.818 L463.214,23.818 L463.241,23.791 L469.844,23.791 L469.871,23.818 Z"/>
3 | </svg>


--------------------------------------------------------------------------------
/source/img/razor-top-black.svg:
--------------------------------------------------------------------------------
1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920px" height="40px">
2 | <path fill-rule="evenodd" fill="rgb(0, 0, 0)" d="M1827.156,15.021 L1827.129,14.994 L1833.785,14.994 L1833.759,15.021 L1827.156,15.021 ZM1824.965,24.036 L1835.969,24.036 L1830.461,18.558 L1833.759,15.021 L1920.000,15.021 L1920.000,39.075 L0.001,39.075 L0.001,15.013 L271.884,15.013 L279.537,6.930 L292.458,6.930 L308.426,24.036 L308.449,24.013 L308.467,24.036 L317.638,15.021 L463.241,15.021 L466.539,18.558 L461.031,24.036 L472.035,24.036 L466.539,18.558 L469.844,15.021 L551.557,15.021 L556.251,10.578 L565.497,1.358 L571.663,7.066 L602.910,7.055 L607.919,7.055 L620.578,19.983 L654.209,19.983 L661.448,12.957 L735.709,12.995 L741.480,18.554 L750.129,9.930 L753.020,12.995 L918.181,12.957 L930.942,0.066 L954.993,24.036 L955.000,24.024 L955.012,24.036 L964.064,15.013 L967.906,15.013 L970.005,17.106 L966.670,20.419 L973.326,20.419 L970.005,17.106 L972.067,15.055 L1050.000,15.023 L1050.000,15.013 L1064.030,15.017 L1072.000,15.013 L1072.000,15.019 L1225.933,15.055 L1227.994,17.106 L1224.674,20.419 L1231.331,20.419 L1227.994,17.106 L1230.094,15.013 L1233.936,15.013 L1242.989,24.036 L1243.000,24.024 L1243.007,24.036 L1267.058,0.066 L1279.819,12.957 L1368.980,12.995 L1371.871,9.930 L1380.520,18.554 L1386.290,13.057 L1635.552,13.019 L1642.790,19.983 L1676.422,19.983 L1689.080,6.992 L1725.337,7.003 L1731.502,1.358 L1740.749,10.578 L1745.443,15.021 L1827.156,15.021 L1830.461,18.558 L1824.965,24.036 ZM341.624,18.857 L339.889,18.857 L339.889,24.036 L341.624,24.036 L341.624,18.857 ZM344.248,18.857 L342.518,18.857 L342.518,24.036 L344.248,24.036 L344.248,18.857 ZM356.370,18.857 L354.640,18.857 L354.640,24.036 L356.370,24.036 L356.370,18.857 ZM377.168,18.857 L371.973,18.857 L371.973,24.036 L377.168,24.036 L377.168,18.857 ZM584.675,12.348 L582.941,12.348 L582.941,14.073 L584.675,14.073 L584.675,12.348 ZM591.316,12.348 L589.582,12.348 L589.582,17.526 L591.316,17.526 L591.316,12.348 ZM604.751,12.348 L603.017,12.348 L603.017,14.073 L604.751,14.073 L604.751,12.348 ZM604.751,15.802 L603.017,15.802 L603.017,17.526 L604.751,17.526 L604.751,15.802 ZM1693.983,12.348 L1692.249,12.348 L1692.249,14.073 L1693.983,14.073 L1693.983,12.348 ZM1693.983,15.802 L1692.249,15.802 L1692.249,17.526 L1693.983,17.526 L1693.983,15.802 ZM1707.418,12.348 L1705.683,12.348 L1705.683,17.526 L1707.418,17.526 L1707.418,12.348 ZM1714.059,12.348 L1712.324,12.348 L1712.324,14.073 L1714.059,14.073 L1714.059,12.348 ZM463.214,14.994 L469.871,14.994 L469.844,15.021 L463.241,15.021 L463.214,14.994 ZM754.222,5.976 L750.129,9.930 L746.025,5.976 L754.222,5.976 ZM1375.975,5.976 L1371.871,9.930 L1367.778,5.976 L1375.975,5.976 Z"/>
3 | </svg>


--------------------------------------------------------------------------------
/source/js/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 |     "extends": "../../.eslintrc.json",
3 |     "env": {
4 |         "browser": true,
5 |         "jquery": true,
6 |         "node": false
7 |     }
8 | }


--------------------------------------------------------------------------------
/source/js/animation.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |     function $() {
 3 |         return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
 4 |     }
 5 | 
 6 |     $('body > .navbar, body > .section, body > .footer').forEach(element => {
 7 |         element.style.transition = '0s';
 8 |         element.style.opacity = '0';
 9 |     });
10 |     document.querySelector('body > .navbar').style.transform = 'translateY(-100px)';
11 |     [
12 |         '.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
13 |         '.column-left > .card, .column-right-shadow > .card',
14 |         '.column-right > .card'
15 |     ].forEach(selector => {
16 |         $(selector).forEach(element => {
17 |             element.style.transition = '0s';
18 |             element.style.opacity = '0';
19 |             element.style.transform = 'scale(0.8)';
20 |             element.style.transformOrigin = 'center top';
21 |         });
22 |     });
23 |     // disable jump to location.hash
24 |     if (window.location.hash) {
25 |         window.scrollTo(0, 0);
26 |         setTimeout(() => window.scrollTo(0, 0));
27 |     }
28 | 
29 |     setTimeout(() => {
30 |         $('body > .navbar, body > .section, body > .footer').forEach(element => {
31 |             element.style.opacity = '1';
32 |             element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
33 |         });
34 |         document.querySelector('body > .navbar').style.transform = 'translateY(0)';
35 | 
36 |         let i = 1;
37 |         [
38 |             '.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
39 |             '.column-left > .card, .column-right-shadow > .card',
40 |             '.column-right > .card'
41 |         ].forEach(selector => {
42 |             $(selector).forEach(element => {
43 |                 setTimeout(() => {
44 |                     element.style.opacity = '1';
45 |                     element.style.transform = '';
46 |                     element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
47 |                 }, i * 100);
48 |                 i++;
49 |             });
50 |         });
51 | 
52 |         // jump to location.hash
53 |         if (window.location.hash) {
54 |             setTimeout(() => {
55 |                 const id = '#' + CSS.escape(window.location.hash.substring(1));
56 |                 const target = document.querySelector(id);
57 |                 if (target) {
58 |                     target.scrollIntoView({ behavior: 'smooth' });
59 |                 }
60 |             }, i * 100);
61 |         }
62 |     });
63 | }());
64 | 


--------------------------------------------------------------------------------
/source/js/back_to_top.js:
--------------------------------------------------------------------------------
  1 | $(document).ready(() => {
  2 |     const $button = $('#back-to-top');
  3 |     const $footer = $('footer.footer');
  4 |     const $mainColumn = $('.column-main');
  5 |     const $leftSidebar = $('.column-left');
  6 |     const $rightSidebar = $('.column-right');
  7 |     let lastScrollTop = 0;
  8 |     const rightMargin = 20;
  9 |     const bottomMargin = 20;
 10 |     let lastState = null;
 11 |     const state = {
 12 |         base: {
 13 |             classname: 'card has-text-centered',
 14 |             left: '',
 15 |             width: 64,
 16 |             bottom: bottomMargin
 17 |         }
 18 |     };
 19 |     state['desktop-hidden'] = Object.assign({}, state.base, {
 20 |         classname: state.base.classname + ' rise-up'
 21 |     });
 22 |     state['desktop-visible'] = Object.assign({}, state['desktop-hidden'], {
 23 |         classname: state['desktop-hidden'].classname + ' fade-in'
 24 |     });
 25 |     state['desktop-dock'] = Object.assign({}, state['desktop-visible'], {
 26 |         classname: state['desktop-visible'].classname + ' fade-in is-rounded',
 27 |         width: 40
 28 |     });
 29 |     state['mobile-hidden'] = Object.assign({}, state.base, {
 30 |         classname: state.base.classname + ' fade-in',
 31 |         right: rightMargin
 32 |     });
 33 |     state['mobile-visible'] = Object.assign({}, state['mobile-hidden'], {
 34 |         classname: state['mobile-hidden'].classname + ' rise-up'
 35 |     });
 36 | 
 37 |     function isStateEquals(prev, next) {
 38 |         return ![].concat(Object.keys(prev), Object.keys(next)).some(key => {
 39 |             return !Object.prototype.hasOwnProperty.call(prev, key)
 40 |                 || !Object.prototype.hasOwnProperty.call(next, key)
 41 |                 || next[key] !== prev[key];
 42 |         });
 43 |     }
 44 | 
 45 |     function applyState(state) {
 46 |         if (lastState !== null && isStateEquals(lastState, state)) {
 47 |             return;
 48 |         }
 49 |         $button.attr('class', state.classname);
 50 |         for (const prop in state) {
 51 |             if (prop === 'classname') {
 52 |                 continue;
 53 |             }
 54 |             $button.css(prop, state[prop]);
 55 |         }
 56 |         lastState = state;
 57 |     }
 58 | 
 59 |     function isDesktop() {
 60 |         return window.innerWidth >= 1078;
 61 |     }
 62 | 
 63 |     function isTablet() {
 64 |         return window.innerWidth >= 768 && !isDesktop();
 65 |     }
 66 | 
 67 |     function isScrollUp() {
 68 |         return $(window).scrollTop() < lastScrollTop && $(window).scrollTop() > 0;
 69 |     }
 70 | 
 71 |     function hasLeftSidebar() {
 72 |         return $leftSidebar.length > 0;
 73 |     }
 74 | 
 75 |     function hasRightSidebar() {
 76 |         return $rightSidebar.length > 0;
 77 |     }
 78 | 
 79 |     function getRightSidebarBottom() {
 80 |         if (!hasRightSidebar()) {
 81 |             return 0;
 82 |         }
 83 |         return Math.max.apply(null, $rightSidebar.find('.widget').map(function() {
 84 |             return $(this).offset().top + $(this).outerHeight(true);
 85 |         }));
 86 |     }
 87 | 
 88 |     function getScrollTop() {
 89 |         return $(window).scrollTop();
 90 |     }
 91 | 
 92 |     function getScrollBottom() {
 93 |         return $(window).scrollTop() + $(window).height();
 94 |     }
 95 | 
 96 |     function getButtonWidth() {
 97 |         return $button.outerWidth(true);
 98 |     }
 99 | 
100 |     function getButtonHeight() {
101 |         return $button.outerHeight(true);
102 |     }
103 | 
104 |     function updateScrollTop() {
105 |         lastScrollTop = $(window).scrollTop();
106 |     }
107 | 
108 |     function update() {
109 |         // desktop mode or tablet mode with only right sidebar enabled
110 |         if (isDesktop() || (isTablet() && !hasLeftSidebar() && hasRightSidebar())) {
111 |             let nextState;
112 |             const padding = ($mainColumn.outerWidth() - $mainColumn.width()) / 2;
113 |             const maxLeft = $(window).width() - getButtonWidth() - rightMargin;
114 |             const maxBottom = $footer.offset().top + (getButtonHeight() / 2) + bottomMargin;
115 |             if (getScrollTop() === 0 || getScrollBottom() < getRightSidebarBottom() + padding + getButtonHeight()) {
116 |                 nextState = state['desktop-hidden'];
117 |             } else if (getScrollBottom() < maxBottom) {
118 |                 nextState = state['desktop-visible'];
119 |             } else {
120 |                 nextState = Object.assign({}, state['desktop-dock'], {
121 |                     bottom: getScrollBottom() - maxBottom + bottomMargin
122 |                 });
123 |             }
124 | 
125 |             const left = $mainColumn.offset().left + $mainColumn.outerWidth() + padding;
126 |             nextState = Object.assign({}, nextState, {
127 |                 left: Math.min(left, maxLeft)
128 |             });
129 |             applyState(nextState);
130 |         } else {
131 |             // mobile and tablet mode
132 |             if (!isScrollUp()) {
133 |                 applyState(state['mobile-hidden']);
134 |             } else {
135 |                 applyState(state['mobile-visible']);
136 |             }
137 |             updateScrollTop();
138 |         }
139 |     }
140 | 
141 |     update();
142 |     $(window).resize(update);
143 |     $(window).scroll(update);
144 | 
145 |     $('#back-to-top').on('click', () => {
146 |         if (CSS && CSS.supports && CSS.supports('(scroll-behavior: smooth)')) {
147 |             window.scroll({ top: 0, behavior: 'smooth' });
148 |         } else {
149 |             $('body, html').animate({ scrollTop: 0 }, 400);
150 |         }
151 |     });
152 | });
153 | 


--------------------------------------------------------------------------------
/source/js/column.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |     function $() {
 3 |         return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
 4 |     }
 5 | 
 6 |     // copy widgets in the right column, when exist, to the bottom of the left column
 7 |     if ($('.columns .column-right').length && $('.columns .column-right-shadow').length && !$('.columns .column-right-shadow')[0].children.length) {
 8 |         for (const child of $('.columns .column-right')[0].children) {
 9 |             $('.columns .column-right-shadow')[0].append(child.cloneNode(true));
10 |         }
11 |     }
12 | }());
13 | 


--------------------------------------------------------------------------------
/source/js/main.js:
--------------------------------------------------------------------------------
  1 | /* eslint-disable node/no-unsupported-features/node-builtins */
  2 | (function($, moment, ClipboardJS, config) {
  3 |     $('.article img:not(".not-gallery-item")').each(function() {
  4 |         // wrap images with link and add caption if possible
  5 |         if ($(this).parent('a').length === 0) {
  6 |             $(this).wrap('<a class="gallery-item" href="' + $(this).attr('src') + '"></a>');
  7 |             if (this.alt) {
  8 |                 $(this).after('<p class="has-text-centered is-size-6 caption">' + this.alt + '</p>');
  9 |             }
 10 |         }
 11 |     });
 12 | 
 13 |     if (typeof $.fn.lightGallery === 'function') {
 14 |         $('.article').lightGallery({ selector: '.gallery-item' });
 15 |     }
 16 |     if (typeof $.fn.justifiedGallery === 'function') {
 17 |         if ($('.justified-gallery > p > .gallery-item').length) {
 18 |             $('.justified-gallery > p > .gallery-item').unwrap();
 19 |         }
 20 |         $('.justified-gallery').justifiedGallery();
 21 |     }
 22 | 
 23 |     if (typeof moment === 'function') {
 24 |         $('.article-meta time').each(function() {
 25 |             $(this).text(moment($(this).attr('datetime')).fromNow());
 26 |         });
 27 |     }
 28 | 
 29 |     $('.article > .content > table').each(function() {
 30 |         if ($(this).width() > $(this).parent().width()) {
 31 |             $(this).wrap('<div class="table-overflow"></div>');
 32 |         }
 33 |     });
 34 | 
 35 |     function adjustNavbar() {
 36 |         const navbarWidth = $('.navbar-main .navbar-start').outerWidth() + $('.navbar-main .navbar-end').outerWidth();
 37 |         if ($(document).outerWidth() < navbarWidth) {
 38 |             $('.navbar-main .navbar-menu').addClass('justify-content-start');
 39 |         } else {
 40 |             $('.navbar-main .navbar-menu').removeClass('justify-content-start');
 41 |         }
 42 |     }
 43 |     adjustNavbar();
 44 |     $(window).resize(adjustNavbar);
 45 | 
 46 |     function toggleFold(codeBlock, isFolded) {
 47 |         const $toggle = $(codeBlock).find('.fold i');
 48 |         !isFolded ? $(codeBlock).removeClass('folded') : $(codeBlock).addClass('folded');
 49 |         !isFolded ? $toggle.removeClass('fa-angle-right') : $toggle.removeClass('fa-angle-down');
 50 |         !isFolded ? $toggle.addClass('fa-angle-down') : $toggle.addClass('fa-angle-right');
 51 |     }
 52 | 
 53 |     function createFoldButton(fold) {
 54 |         return '<span class="fold">' + (fold === 'unfolded' ? '<i class="fas fa-angle-down"></i>' : '<i class="fas fa-angle-right"></i>') + '</span>';
 55 |     }
 56 | 
 57 |     $('figure.highlight table').wrap('<div class="highlight-body">');
 58 |     if (typeof config !== 'undefined'
 59 |         && typeof config.article !== 'undefined'
 60 |         && typeof config.article.highlight !== 'undefined') {
 61 | 
 62 |         $('figure.highlight').addClass('hljs');
 63 |         $('figure.highlight .code .line span').each(function() {
 64 |             const classes = $(this).attr('class').split(/\s+/);
 65 |             for (const cls of classes) {
 66 |                 $(this).addClass('hljs-' + cls);
 67 |                 $(this).removeClass(cls);
 68 |             }
 69 |         });
 70 | 
 71 | 
 72 |         const clipboard = config.article.highlight.clipboard;
 73 |         const fold = config.article.highlight.fold.trim();
 74 | 
 75 |         $('figure.highlight').each(function() {
 76 |             if ($(this).find('figcaption').length) {
 77 |                 $(this).find('figcaption').addClass('level is-mobile');
 78 |                 $(this).find('figcaption').append('<div class="level-left">');
 79 |                 $(this).find('figcaption').append('<div class="level-right">');
 80 |                 $(this).find('figcaption div.level-left').append($(this).find('figcaption').find('span'));
 81 |                 $(this).find('figcaption div.level-right').append($(this).find('figcaption').find('a'));
 82 |             } else {
 83 |                 if (clipboard || fold) {
 84 |                     $(this).prepend('<figcaption class="level is-mobile"><div class="level-left"></div><div class="level-right"></div></figcaption>');
 85 |                 }
 86 |             }
 87 |         });
 88 | 
 89 |         if (typeof ClipboardJS !== 'undefined' && clipboard) {
 90 |             $('figure.highlight').each(function() {
 91 |                 const id = 'code-' + Date.now() + (Math.random() * 1000 | 0);
 92 |                 const button = '<a href="javascript:;" class="copy" title="Copy" data-clipboard-target="#' + id + ' .code"><i class="fas fa-copy"></i></a>';
 93 |                 $(this).attr('id', id);
 94 |                 $(this).find('figcaption div.level-right').append(button);
 95 |             });
 96 |             new ClipboardJS('.highlight .copy'); // eslint-disable-line no-new
 97 |         }
 98 | 
 99 |         if (fold) {
100 |             $('figure.highlight').each(function() {
101 |                 $(this).addClass('foldable'); // add 'foldable' class as long as fold is enabled
102 | 
103 |                 if ($(this).find('figcaption').find('span').length > 0) {
104 |                     const span = $(this).find('figcaption').find('span');
105 |                     if (span[0].innerText.indexOf('>folded') > -1) {
106 |                         span[0].innerText = span[0].innerText.replace('>folded', '');
107 |                         $(this).find('figcaption div.level-left').prepend(createFoldButton('folded'));
108 |                         toggleFold(this, true);
109 |                         return;
110 |                     }
111 |                 }
112 |                 $(this).find('figcaption div.level-left').prepend(createFoldButton(fold));
113 |                 toggleFold(this, fold === 'folded');
114 |             });
115 | 
116 |             $('figure.highlight figcaption .level-left').click(function() {
117 |                 const $code = $(this).closest('figure.highlight');
118 |                 toggleFold($code.eq(0), !$code.hasClass('folded'));
119 |             });
120 |         }
121 |     }
122 | 
123 |     const $toc = $('#toc');
124 |     if ($toc.length > 0) {
125 |         const $mask = $('<div>');
126 |         $mask.attr('id', 'toc-mask');
127 | 
128 |         $('body').append($mask);
129 | 
130 |         function toggleToc() { // eslint-disable-line no-inner-declarations
131 |             $toc.toggleClass('is-active');
132 |             $mask.toggleClass('is-active');
133 |         }
134 | 
135 |         $toc.on('click', toggleToc);
136 |         $mask.on('click', toggleToc);
137 |         $('.navbar-main .catalogue').on('click', toggleToc);
138 |     }
139 | }(jQuery, window.moment, window.ClipboardJS, window.IcarusThemeSettings));
140 | 


--------------------------------------------------------------------------------
/source/js/pjax.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |     // eslint-disable-next-line no-unused-vars
 3 |     let pjax;
 4 | 
 5 |     function initPjax() {
 6 |         try {
 7 |             const Pjax = window.Pjax || function() {};
 8 |             pjax = new Pjax({
 9 |                 selectors: [
10 |                     '[data-pjax]',
11 |                     '.pjax-reload',
12 |                     'head title',
13 |                     '.columns',
14 |                     '.navbar-start',
15 |                     '.navbar-end',
16 |                     '.searchbox link',
17 |                     '.searchbox script',
18 |                     '#back-to-top',
19 |                     '#comments link',
20 |                     '#comments script'
21 |                 ],
22 |                 cacheBust: false
23 |             });
24 |         } catch (e) {
25 |             console.warn('PJAX error: ' + e);
26 |         }
27 |     }
28 | 
29 |     // // Listen for start of Pjax
30 |     // document.addEventListener('pjax:send', function() {
31 |     //     return;
32 |     //     // TODO pace start loading animation
33 |     // })
34 | 
35 |     // Listen for completion of Pjax
36 |     document.addEventListener('pjax:complete', () => {
37 |         // Plugin [MathJax] reload logic
38 |         if (window.MathJax) {
39 |             try {
40 |                 window.MathJax.typesetPromise && window.MathJax.typesetPromise();
41 |             } catch (e) {
42 |                 console.error('MathJax reload error:', e);
43 |             }
44 |         }
45 |         // Plugin [Busuanzi] reload logic
46 |         if (window.bszCaller && window.bszTag) {
47 |             window.bszCaller.fetch('//busuanzi.ibruce.info/busuanzi?jsonpCallback=BusuanziCallback', a => {
48 |                 window.bszTag.texts(a);
49 |                 window.bszTag.shows();
50 |             });
51 |         }
52 | 
53 |         // TODO pace stop loading animation
54 |     });
55 | 
56 |     document.addEventListener('DOMContentLoaded', () => initPjax());
57 | }());
58 | 


--------------------------------------------------------------------------------