Showing preview only (207K chars total). Download the full file or copy to clipboard to get everything.
Repository: ppoffice/hexo-theme-icarus
Branch: master
Commit: 76d8cd019700
Files: 122
Total size: 183.3 KB
Directory structure:
gitextract_bspt8wyp/
├── .eslintignore
├── .eslintrc.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── Bug反馈.md
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ ├── feature_request.md
│ │ └── 功能建议.md
│ ├── PULL_REQUEST_TEMPLATE/
│ │ └── pull_request_template.md
│ ├── dependabot.yml
│ ├── stale.yml
│ └── workflows/
│ ├── github-release.yml
│ ├── lint.yml
│ ├── npm-publish.yml
│ └── test.yml
├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── include/
│ ├── config.js
│ ├── dependency.js
│ ├── migration/
│ │ ├── head.js
│ │ ├── v2_v3.js
│ │ ├── v3_v4.js
│ │ ├── v4_v5.js
│ │ └── v5_v5.1.js
│ ├── register.js
│ ├── schema/
│ │ ├── comment/
│ │ │ └── .gitkeep
│ │ ├── common/
│ │ │ ├── article.json
│ │ │ ├── comment.json
│ │ │ ├── donates.json
│ │ │ ├── footer.json
│ │ │ ├── head.json
│ │ │ ├── navbar.json
│ │ │ ├── plugins.json
│ │ │ ├── providers.json
│ │ │ ├── search.json
│ │ │ ├── share.json
│ │ │ ├── sidebar.json
│ │ │ └── widgets.json
│ │ ├── config.json
│ │ ├── donate/
│ │ │ └── .gitkeep
│ │ ├── misc/
│ │ │ └── .gitkeep
│ │ ├── plugin/
│ │ │ ├── animejs.json
│ │ │ ├── back_to_top.json
│ │ │ └── pjax.json
│ │ ├── search/
│ │ │ └── .gitkeep
│ │ ├── share/
│ │ │ └── .gitkeep
│ │ └── widget/
│ │ └── profile.json
│ ├── style/
│ │ ├── article.styl
│ │ ├── base.styl
│ │ ├── button.styl
│ │ ├── card.styl
│ │ ├── codeblock.styl
│ │ ├── donate.styl
│ │ ├── footer.styl
│ │ ├── helper.styl
│ │ ├── navbar.styl
│ │ ├── pagination.styl
│ │ ├── plugin.styl
│ │ ├── responsive.styl
│ │ ├── search.styl
│ │ ├── timeline.styl
│ │ └── widget.styl
│ └── util/
│ └── console.js
├── languages/
│ ├── de.yml
│ ├── en.yml
│ ├── es.yml
│ ├── fr.yml
│ ├── id.yml
│ ├── it.yml
│ ├── ja.yml
│ ├── ko.yml
│ ├── pl.yml
│ ├── pt-BR.yml
│ ├── ru.yml
│ ├── sv.yml
│ ├── tk.yml
│ ├── tr.yml
│ ├── vn.yml
│ ├── zh-CN.yml
│ └── zh-TW.yml
├── layout/
│ ├── archive.jsx
│ ├── categories.jsx
│ ├── category.jsx
│ ├── comment/
│ │ └── .gitkeep
│ ├── common/
│ │ ├── article.jsx
│ │ ├── comment.jsx
│ │ ├── donates.jsx
│ │ ├── footer.jsx
│ │ ├── head.jsx
│ │ ├── navbar.jsx
│ │ ├── plugins.jsx
│ │ ├── scripts.jsx
│ │ ├── search.jsx
│ │ ├── share.jsx
│ │ └── widgets.jsx
│ ├── donate/
│ │ └── .gitkeep
│ ├── index.jsx
│ ├── layout.jsx
│ ├── misc/
│ │ └── .gitkeep
│ ├── page.jsx
│ ├── plugin/
│ │ ├── animejs.jsx
│ │ ├── back_to_top.jsx
│ │ └── pjax.jsx
│ ├── post.jsx
│ ├── search/
│ │ └── .gitkeep
│ ├── share/
│ │ └── .gitkeep
│ ├── tag.jsx
│ ├── tags.jsx
│ └── widget/
│ └── profile.jsx
├── package.json
├── scripts/
│ └── index.js
└── source/
├── css/
│ ├── cyberpunk.styl
│ ├── default.styl
│ └── style.styl
└── js/
├── .eslintrc.json
├── animation.js
├── back_to_top.js
├── column.js
├── main.js
└── pjax.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
node_modules/
================================================
FILE: .eslintrc.json
================================================
{
"extends": [
"hexo",
"plugin:react/recommended",
"plugin:json/recommended"
],
"settings": {
"node": {
"tryExtensions": [
".js",
".jsx",
".json"
]
},
"react": {
"version": "16.0"
}
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module",
"ecmaVersion": "latest"
},
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-vars": "error",
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"react/no-unknown-property": [
"error",
{
"ignore": [
"class",
"onclick",
"onload",
"onsubmit",
"crossorigin"
]
}
],
"react/react-in-jsx-scope": [
"off"
],
"react/prop-types": [
"off"
],
"react/display-name": [
"off"
],
"react/jsx-key": [
"off"
],
"react/jsx-no-target-blank": [
"error",
{
"allowReferrer": true
}
]
}
}
================================================
FILE: .github/ISSUE_TEMPLATE/Bug反馈.md
================================================
---
name: Bug反馈
about: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。
title: [Bug] 问题概述
labels: ''
assignees: ''
---
> 确保你在提交Bug反馈之前仔细阅读了[Hexo文档](https://hexo.io/zh-cn/),[Icarus用户指南](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97/),和[GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues)来了解你的问题是否已经被他人提出过。
**Bug描述**
简洁清晰地描述你遇到的Bug是什么。
**系统与环境**
列出你的Hexo和Icarus的版本和配置。
- Hexo,操作系统,和Node.js的版本(使用`hexo version`命令来查看)
- 站点配置文件`_config.yml`
- 主题配置文件`_config.icarus.yml`或`themes/icarus/_config.yml`
- 其他额外的配置文件(文章front-matter,`_config.post.yml`,或`_config.page.yml`)
- 浏览器版本(如Firefox 70.0,Chrome Android 80.0)
**复现方式**
列出复现这个Bug的步骤,如:
1. 访问‘...’
2. 点击’...‘
3. 下拉到‘...’
4. 出现‘...’的错误
**期望行为**
简洁清晰地描述没有这个情况下你期望得到的结果。
**截图**
如果可以的话,请附上几张截图来帮助说明你遇到的问题。
**额外上下文**
附上与问题有关的其他上下文信息。
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Please follow this template if you are reporting a bug, or your issue may be closed without further notice.
title: [Bug] Bug summary
labels: ''
assignees: ''
---
> Make sure you go through the [Hexo docs](https://hexo.io), [Icarus user manual](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus-User-Guide/), and [GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues) to see if the bug you are reporting has been already addressed by others.
**Describe the bug**
A clear and concise description of what the bug is.
**System and Environment**
The version and configuration of Hexo and Icarus.
- Hexo, OS, and node version (use `hexo version` command to view these information)
- Site configuration file `_config.yml`
- Theme configuration file `_config.icarus.yml` or `themes/icarus/_config.yml`
- Any additional theme configuration files (post front-matter, `_config.post.yml`, or `_config.page.yml`)
- Browser and version (e.g., Firefox 70.0, Chrome Android 80.0)
**To Reproduce**
Steps to reproduce the behavior, such as:
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. '...' error appears
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/ppoffice/hexo-theme-icarus/discussions
about: Redirect your Icarus usage questions to here.
- name: GitHub讨论组
url: https://github.com/ppoffice/hexo-theme-icarus/discussions
about: 与Icarus使用相关的问题请转至这里。
- name: Bug Report
url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=bug_report.md
about: Please follow this template if you are reporting a bug, or your issue may be closed without further notice.
- name: Bug反馈
url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=Bug反馈.md
about: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。
- name: Feature Request
url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=feature_request.md
about: Please follow this template if you are requesting a new feature, or your issue may be closed without further notice.
- name: 功能建议
url: https://github.com/ppoffice/hexo-theme-icarus/issues/new?template=功能建议.md
about: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature Request
about: Please follow this template if you are requesting a new feature, or your issue may be closed without further notice.
title: [FEAT] Feature request summary
labels: ''
assignees: ''
---
> Make sure you go through the [Hexo docs](https://hexo.io), [Icarus user manual](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus-User-Guide/), and [GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues) to see if the feature you are requesting has been already addressed by others.
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is (e.g., I'm always frustrated when [...]).
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/功能建议.md
================================================
---
name: 功能建议
about: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。
title: [FEAT] 功能建议概述
labels: ''
assignees: ''
---
> 确保你在提交功能建议之前仔细阅读了[Hexo文档](https://hexo.io/zh-cn/),[Icarus用户指南](https://ppoffice.github.io/hexo-theme-icarus/tags/Icarus%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97/),和[GitHub issues](https://github.com/ppoffice/hexo-theme-icarus/issues)来了解你的建议是否已经被他人提出过。
**你的功能建议与某个使用问题相关么?请详述。**
简洁清晰地描述你遇到的问题是什么(如:我在使用...的时候遇到了...)。
**描述你想要的解决方案**
简洁清晰地描述你想要的解决方案可以达到的效果。
**描述你考虑过的替代办法**
简洁清晰地描述你考虑过的替代解决方案或是新功能。
**额外上下文**
附上与功能请求有关的其他上下文信息或者截图。
================================================
FILE: .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
================================================
---
name: Pull Request
about: Suggest a code change to this project.
title: ''
labels: ''
assignees: ''
---
**Note 0**
Please review [the contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) before making this pull request.
**Note 1**
Please break up your pull request into multiple smaller requests if it contains multiple bug fixes
or new features.
Each pull request should have one bug fix or new feature only for better code maintainability.
**Note 2**
Many components of this theme, including core functions, some Hexo extensions, widgets and plugins,
have been moved to [ppoffice/hexo-component-inferno](https://github.com/ppoffice/hexo-component-inferno).
Please make a pull request to that repository instead of this one if your changes are related to
the above components.
**Detailed description**
> Please use the [Icarus issue template](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) if it is a bug fix.
> Please use the [Icarus feature request template](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) if it is a bug fix.
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'daily'
================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 14
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- bug:core
- bug:extension
- bug:general
- feature:core
- feature:extension
- feature:general
- tutorial:v1
- tutorial:v2
- tutorial:v3
- tutorial:v4
- tutorial:v5
- tutorial:v6
- tutorial:v7
- tutorial:v8
- tutorial:v9
- Gitalk
- utterances
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
================================================
FILE: .github/workflows/github-release.yml
================================================
name: GitHub Release
on:
push:
tags:
- '*'
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: ncipollo/release-action@v1
with:
tag: ${{ github.ref }}
name: ${{ github.ref }}
draft: true
prerelease: false
================================================
FILE: .github/workflows/lint.yml
================================================
name: Code Linting
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: latest
- run: npm install
- run: npm run lint
================================================
FILE: .github/workflows/npm-publish.yml
================================================
name: Node.js Package
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14
registry-url: https://registry.npmjs.org/
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14, latest]
fail-fast: false
steps:
- uses: actions/checkout@v3
with:
repository: hexojs/hexo-starter
ref: dcd18588de8f5c1bcc689c101e2f21726c11c4d6 # pin blog dependencies to support node.js 14
- uses: actions/checkout@v3
with:
path: themes/icarus
- uses: actions/checkout@v3
with:
repository: SukkaLab/hexo-many-posts
path: source/_posts/hexo-many-posts
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: actions/cache@v3
with:
path: node_modules
key: npm-cache
restore-keys: npm-cache
- run: npm install
- run: >
npm install $(node -e "const deps=require('./themes/icarus/package.json').dependencies;
console.log(Object.keys(deps).map(key=>key+'@'+deps[key]).join(' '));")
- run: npm install hexo-tag-embed
- run: npx hexo config theme icarus
- run: time NODE_ENV=production npx hexo g -b
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
_config*.yml*
yarn.lock
# Intellij Idea config file
.idea
*.ipr
*.iws
*.iml
================================================
FILE: .npmignore
================================================
.github/
.eslintignore
.eslintrc.json
.travis.yml
yarn.lock
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines
## Code styles
Please refer to the [.eslintrc.json](https://github.com/ppoffice/hexo-theme-icarus/blob/master/.eslintrc.json).
You can also use `npm run lint` or `yarn lint` to fix code style issues.
## Project versioning
We use [SemVer](http://semver.org/) for versioning.
Any changes to the code base should not be released using an existing version.
## Commit message format
The commit message should follow the [Bluejava commit message format](https://github.com/bluejava/git-commit-guide).
The supported scopes are:
- **core** for changes related to Hexo extensions and theme-specific functions
- **comment** for comment plugin layout, schema, style, or script changes
- **share** for share plugin layout, schema, style, or script changes
- **donate** for donation plugin layout, schema, style, or script changes
- **search** for search plugin layout, schema, style, or script changes
- **widget** for widget layout, schema, style, or script changes
- **plugin** for other plugin layout, schema, style, or script changes
- **i18n** for adding or updating translations
- **test** for testing or linting-related commits
- **build** for build scripts, CI, other development or deployment related commits
- use __\*__ or leave empty to refer to commits that do not have a clear scope
## Submit changes
1. Fork this repository, make changes to it, and run it against some actual Hexo sites to see if
anything is broken.
You should also run `npm run lint` or `yarn lint` to find and fix any code formatting issue.
2. Submit a pull request to our repository. Please make sure you followed the instructions
above.
3. We will review the pull request regularly and inform you of our questions and any changes
that need to be made before we can merge your pull request.
4. We expect your response within two weeks, after which your pull request may be closed if
no activity is shown.
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2020 PPOffice
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<p align="center" class="mb-2">
<img class="not-gallery-item" height="48" src="https://ppoffice.github.io/hexo-theme-icarus/img/logo.svg">
<br> A simple, delicate, and modern theme for the static site generator Hexo.
<br>
<a href="https://ppoffice.github.io/hexo-theme-icarus/">Preview</a> |
<a href="https://ppoffice.github.io/hexo-theme-icarus/categories/">Documentation</a> |
<a href="https://github.com/ppoffice/hexo-theme-icarus/discussions">Discuss on GitHub</a>
<br>
</p>

## :cd: Installation
```shell
$ npm install hexo-theme-icarus
$ hexo config theme icarus
```
Please refer to [Getting Started with Icarus](https://ppoffice.github.io/hexo-theme-icarus/uncategorized/getting-started-with-icarus/)
for more details.
## :gift: Features
### Cyberpunk Theme Variant
Tap into the future cyber world with the newly added Cyberpunk theme variant.
Inspired by [Cyberpunk 2077](https://www.cyberpunk.net).

### Extensive Plugin Support
Icarus includes plentiful search, comment, sharing and other plugins out of the box that makes your
blog feature-rich and powerful.
**[Comment](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/)**
Changyan · Disqus · DisqusJS · Facebook · Gitalk · Gitment ·
Isso · LiveRe · Utterance · Valine
**[Donate Button](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/)**
Afdian.net · Alipay · Buy me a coffee · Patreon · Paypal · Wecat
**[Search](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/)**
Algolia · Baidu · Google CSE · Insight
**[Share](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/)**
AddThis · AddToAny · Baidu Share · Share.js · ShareThis
**[Widgets](https://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/)**
Google Adsense · Archives · Categories · External Site Links ·
Recent Posts · Google Feedburner · Tags · Table of Contents
**[Analytics](https://ppoffice.github.io/hexo-theme-icarus/Plugins/Analytics/icarus-user-guide-web-analytics-plugins/)**
Baidu Statistics · Bing Webmaster · BuSuanZi Web Counter · CNZZ Statistics ·
Google Analytics · Hotjar · StatCounter · Twitter Conversion Tracking
**[Other Plugins](https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/)**
Cookie Consent · LightGallery · Justified Gallery · KaTeX · MathJax ·
Oudated Browser · Page Loading Animations
### Colorful Code Highlight
Icarus directly import stylesheets from the [highlight.js](https://highlightjs.org/) package and makes more than
90 code highlight themes available to you.
<table>
<tr>
<th>Atom One Light</th>
<th>Monokai</th>
<th>Kimbie Dark</th>
</tr>
<tr>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/atom-one-light.png?2"></td>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/monokai.png?2"></td>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/kimbie-dark.png?2"></td>
</tr>
</table>
### Flexible Theme Configuration
Icarus allows you to configure your site on a per-page or per-layout basis.
<div>
<table>
<tr>
<th>_config.yml</th>
<th>post.md</th>
<th>_config.page.yml</th>
</tr>
<tr>
<td>
<pre>widgets:
- type: profile
position: left
- type: recent_posts
position: right</pre>
</td>
<td>
<pre>widgets:
- type: profile
position: left
- type: recent_posts
position: left</pre>
</td>
<td>
<pre>widgets: null
</pre>
</td>
</tr>
<tr>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/default-config.png"></td>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/post-config.png"></td>
<td><img width="266" src="https://ppoffice.github.io/hexo-theme-icarus/gallery/screenshots/layout-config.png"></td>
</tr>
</table>
</div>
### Responsive Layout
Give your audiences best viewing experience with Icarus's mobile-friendly responsive layout.

## :hammer: Development
This project is built with
- [Hexo](https://hexo.io/)
- [Inferno.js](https://infernojs.org/)
- [Stylus](https://stylus-lang.com/)
- [Bulma](https://bulma.io/)
Please refer to the [documentation](https://ppoffice.github.io/hexo-theme-icarus/categories/) and
[contributing guide](https://github.com/ppoffice/hexo-theme-icarus/blob/master/CONTRIBUTING.md) for implementation details.
## :tada: Contribute
If you feel like to help us build a better Icarus, you can
:black_nib: [Submit a tutorial](https://github.com/ppoffice/hexo-theme-icarus/new/site/source/_posts) |
:earth_asia: [Add a translation](https://github.com/ppoffice/hexo-theme-icarus/tree/master/languages) |
:triangular_flag_on_post: [Report a bug](https://github.com/ppoffice/hexo-theme-icarus/issues) |
:electric_plug: [Suggest a new feature](https://github.com/ppoffice/hexo-theme-icarus/pulls)
## :memo: License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/ppoffice/hexo-theme-icarus/blob/master/LICENSE) file for details.
================================================
FILE: include/config.js
================================================
/* eslint no-process-exit: "off" */
const fs = require('fs');
const path = require('path');
const util = require('util');
const crypto = require('crypto');
const createLogger = require('hexo-log');
const yaml = require('hexo-component-inferno/lib/util/yaml');
const { Migrator } = require('hexo-component-inferno/lib/core/migrate');
const { SchemaLoader } = require('hexo-component-inferno/lib/core/schema');
const { yellow } = require('./util/console');
const logger = createLogger.default();
function loadThemeConfig(hexo, cfgPaths) {
const configs = cfgPaths.map(cfgPath => fs.readFileSync(cfgPath))
.map(cfgPath => yaml.parse(cfgPath));
return Object.assign({}, ...configs, hexo.config.theme_config);
}
function generateThemeConfigFile(schema, cfgPath) {
const defaultValue = schema.getDefaultValue();
fs.writeFileSync(cfgPath, defaultValue.toYaml());
}
function hashConfigFile(cfgPath) {
const content = fs.readFileSync(cfgPath);
return crypto.createHash('md5').update(content).digest('hex');
}
function checkConfig(hexo) {
if (!process.argv.includes('--icarus-dont-check-config')) {
logger.info('=== Checking theme configurations ===');
const siteCfgFile = path.join(hexo.base_dir, '_config.yml');
const themeSiteCfg = path.join(hexo.base_dir, '_config.icarus.yml');
const themeDirCfg = path.join(hexo.theme_dir, '_config.yml');
const themeCfgPaths = [themeDirCfg, themeSiteCfg].filter(cfgPath => fs.existsSync(cfgPath));
const themeSiteCfgExample = themeSiteCfg + '.example';
const schemaDir = path.join(hexo.theme_dir, 'include/schema/');
const loader = SchemaLoader.load(require(path.join(schemaDir, 'config.json')), schemaDir);
const schema = loader.getSchema('/config.json');
if (!process.argv.includes('--icarus-dont-generate-config')) {
if (!themeCfgPaths.length) {
logger.warn('None of the following configuration files is found:');
logger.warn(`- ${yellow(themeSiteCfg)}`);
logger.warn(`- ${yellow(themeDirCfg)}`);
logger.info('Generating theme configuration file...');
generateThemeConfigFile(schema, themeSiteCfg);
themeCfgPaths.push(themeSiteCfg);
logger.info(`${yellow(themeSiteCfg)} created successfully.`);
logger.info('To skip configuration generation, use "--icarus-dont-generate-config".');
}
}
let cfg = loadThemeConfig(hexo, themeCfgPaths);
if (!process.argv.includes('--icarus-dont-upgrade-config')) {
const migrator = new Migrator(require(path.join(hexo.theme_dir, 'include/migration/head')));
if (cfg.version && migrator.isOudated(cfg.version)) {
logger.warn(`Your theme configuration is outdated (${cfg.version} < ${migrator.getLatestVersion()}).`);
logger.info('To skip the configuration upgrade, use "--icarus-dont-upgrade-config".');
logger.info('Backing up theme configuration files...');
for (const cfgPath of themeCfgPaths) {
const backupPath = cfgPath + '.' + hashConfigFile(cfgPath);
const relCfgPath = path.relative(hexo.base_dir, cfgPath);
const relBackupPath = path.relative(hexo.base_dir, backupPath);
fs.renameSync(cfgPath, backupPath);
logger.info(`${yellow(relCfgPath)} => ${yellow(relBackupPath)}`);
}
logger.info('Upgrading theme configurations...');
cfg = migrator.migrate(cfg);
fs.writeFileSync(themeSiteCfg, yaml.stringify(cfg));
logger.info(`Theme configurations are written to ${yellow(themeSiteCfg)}.`);
generateThemeConfigFile(schema, themeSiteCfgExample);
logger.info(`Example configurations is at ${yellow(themeSiteCfgExample)}.`);
}
}
const validation = schema.validate(cfg);
if (validation !== true) {
logger.warn('Theme configurations failed one or more checks.');
logger.warn('Icarus may still run, but you will encounter unexcepted results.');
logger.warn('Here is some information for you to correct the configuration file.');
logger.warn(util.inspect(validation));
}
const rootCfg = yaml.parse(fs.readFileSync(siteCfgFile));
if (rootCfg.theme_config) {
logger.warn(`"theme_config" found in ${yellow(siteCfgFile)}.`);
logger.warn(`Please remove theme configurations from ${yellow(siteCfgFile)}.`);
}
}
}
module.exports = hexo => {
try {
checkConfig(hexo);
} catch (e) {
logger.error(e);
logger.error('Theme configuration checking failed.');
logger.info('You may use \'--icarus-dont-check-config\' to skip configuration checking.');
process.exit(-1);
}
};
================================================
FILE: include/dependency.js
================================================
/* eslint no-process-exit: "off" */
const semver = require('semver');
const createLogger = require('hexo-log');
const packageInfo = require('../package.json');
const { yellow, red, green } = require('./util/console');
const logger = createLogger.default();
module.exports = hexo => {
function checkDependency(name, reqVer) {
try {
require.resolve(name);
const version = require(name + '/package.json').version;
if (!semver.satisfies(version, reqVer)) {
logger.error(`Package ${yellow(name)}'s version (${yellow(version)}) does not satisfy the required version (${red(reqVer)}).`);
return false;
}
return true;
} catch (e) {
logger.error(`Package ${yellow(name)} is not installed.`);
}
return false;
}
logger.info('=== Checking package dependencies ===');
const dependencies = Object.assign({}, packageInfo.dependencies);
const missingDeps = Object.keys(dependencies)
.filter(name => !checkDependency(name, dependencies[name]));
if (missingDeps && missingDeps.length) {
logger.error('Please install the missing dependencies your Hexo site root directory:');
logger.error(green('npm install --save ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
logger.error('or:');
logger.error(green('yarn add ' + missingDeps.map(name => `${name}@${dependencies[name]}`).join(' ')));
process.exit(-1);
}
};
================================================
FILE: include/migration/head.js
================================================
module.exports = require('./v5_v5.1');
================================================
FILE: include/migration/v2_v3.js
================================================
const createLogger = require('hexo-log');
const deepmerge = require('deepmerge');
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
const logger = createLogger.default();
module.exports = class extends Migration {
constructor() {
super('3.0.0', null);
}
upgrade(config) {
const result = deepmerge({}, config);
result.head = {
favicon: config.favicon || null,
canonical_url: config.canonical_url || null,
open_graph: config.open_graph || null,
meta: config.meta || null,
rss: config.rss || null
};
delete result.favicon;
delete result.canonical_url;
delete result.open_graph;
delete result.meta;
delete result.rss;
if (result.logo === '/images/logo.svg') {
result.logo = result.logo.replace(/^\/images/, '/img');
}
if (result.head.favicon === '/img/favicon.svg') {
result.head.favicon = result.head.favicon.replace(/^\/images/, '/img');
}
if (result.search && Object.prototype.hasOwnProperty.call(result.search, 'type')) {
switch (result.search.type) {
case 'google-cse':
result.search.type = 'google_cse';
break;
}
}
if (result.comment && Object.prototype.hasOwnProperty.call(result.comment, 'type')) {
switch (result.comment.type) {
case 'changyan':
result.comment.app_id = config.comment.appid;
delete result.comment.appid;
break;
}
}
if (Array.isArray(result.donate) && result.donate.length) {
result.donates = result.donate;
delete result.donate;
}
if (Array.isArray(result.widgets) && result.widgets.length) {
for (const widget of result.widgets) {
if (Object.prototype.hasOwnProperty.call(widget, 'type')) {
switch (widget.type) {
case 'archive':
widget.type = 'archives';
break;
case 'category':
widget.type = 'categories';
break;
case 'tag':
widget.type = 'tags';
break;
case 'tagcloud':
logger.warn('The tagcloud widget has been removed from Icarus in version 3.0.0.');
logger.warn('Please remove it from your configuration file.');
break;
}
}
}
}
if (result.plugins && typeof result.plugins === 'object') {
for (const name in result.plugins) {
switch (name) {
case 'outdated-browser':
result.plugins.outdated_browser = result.plugins[name];
delete result.plugins[name];
break;
case 'back-to-top':
result.plugins.back_to_top = result.plugins[name];
delete result.plugins[name];
break;
case 'baidu-analytics':
result.plugins.baidu_analytics = result.plugins[name];
delete result.plugins[name];
break;
case 'google-analytics':
result.plugins.google_analytics = result.plugins[name];
delete result.plugins[name];
break;
}
}
}
return result;
}
};
================================================
FILE: include/migration/v3_v4.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
module.exports = class extends Migration {
constructor() {
super('4.0.0', null);
}
upgrade(config) {
if (typeof config.article === 'object') {
delete config.article.thumbnail;
}
return config;
}
};
================================================
FILE: include/migration/v4_v5.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
module.exports = class extends Migration {
constructor() {
super('5.0.0', null);
}
upgrade(config) {
return config;
}
};
================================================
FILE: include/migration/v5_v5.1.js
================================================
const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;
module.exports = class extends Migration {
constructor() {
super('5.1.0', null);
}
upgrade(config) {
// Upgrade Waline configurations from v1 to v2.
const comment = config.comment || {};
const renamedOptions = {
'visitor': 'pageview',
'uploadImage': 'image_uploader',
'highlight': 'highlighter',
'math': 'tex_renderer'
};
if (comment.type === 'waline') {
for (const option in renamedOptions) {
if (typeof comment[option] !== 'undefined') {
if (typeof comment[renamedOptions[option]] === 'undefined') {
comment[renamedOptions[option]] = comment[option];
}
delete comment[option];
}
}
}
return config;
}
};
================================================
FILE: include/register.js
================================================
const createLogger = require('hexo-log');
const logger = createLogger.default();
module.exports = hexo => {
logger.info('=== Registering Hexo extensions ===');
require('hexo-component-inferno/lib/hexo/filter/locals')(hexo);
require('hexo-component-inferno/lib/hexo/generator/assets')(hexo);
require('hexo-component-inferno/lib/hexo/generator/insight')(hexo);
require('hexo-component-inferno/lib/hexo/generator/categories')(hexo);
require('hexo-component-inferno/lib/hexo/generator/category')(hexo);
require('hexo-component-inferno/lib/hexo/generator/manifest')(hexo);
require('hexo-component-inferno/lib/hexo/generator/tags')(hexo);
require('hexo-component-inferno/lib/hexo/helper/cdn')(hexo);
require('hexo-component-inferno/lib/hexo/helper/page')(hexo);
require('hexo-component-inferno/lib/hexo/tag/message')(hexo);
require('hexo-component-inferno/lib/hexo/tag/tabs')(hexo);
require('hexo-component-inferno/lib/core/view').init(hexo);
};
================================================
FILE: include/schema/comment/.gitkeep
================================================
================================================
FILE: include/schema/common/article.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/article.json",
"description": "Article related configurations",
"type": "object",
"properties": {
"highlight": {
"type": "object",
"description": "Code highlight settings",
"properties": {
"theme": {
"type": "string",
"description": "Code highlight themes\nhttps://github.com/highlightjs/highlight.js/tree/master/src/styles",
"default": "atom-one-light",
"nullable": true
},
"clipboard": {
"type": "boolean",
"description": "Show copy code button",
"default": true,
"nullable": true
},
"fold": {
"type": "string",
"description": "Default folding status of the code blocks. Can be \"\", \"folded\", \"unfolded\"",
"enum": [
"",
"folded",
"unfolded"
],
"default": "unfolded",
"nullable": true
}
},
"nullable": true
},
"readtime": {
"type": "boolean",
"description": "Whether to show estimated article reading time",
"default": true,
"nullable": true
},
"update_time": {
"type": ["boolean", "string"],
"description": "Whether to show updated time. For \"auto\", shows article update time only when page.updated is set and it is different from page.date",
"default": true,
"enum": [true, false, "auto"],
"nullable": true
},
"licenses": {
"$ref": "/misc/poly_links.json",
"description": "Article licensing block",
"examples": [
{
"Creative Commons": {
"icon": "fab fa-creative-commons",
"url": "https://creativecommons.org/"
},
"Attribution": {
"icon": "fab fa-creative-commons-by",
"url": "https://creativecommons.org/licenses/by/4.0/"
},
"Noncommercial": {
"icon": "fab fa-creative-commons-nc",
"url": "https://creativecommons.org/licenses/by-nc/4.0/"
}
}
]
}
}
}
================================================
FILE: include/schema/common/comment.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/comment.json",
"description": "Comment plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/",
"type": "object",
"oneOf": [
{
"$ref": "/comment/disqus.json"
},
{
"$ref": "/comment/changyan.json"
},
{
"$ref": "/comment/disqusjs.json"
},
{
"$ref": "/comment/facebook.json"
},
{
"$ref": "/comment/giscus.json"
},
{
"$ref": "/comment/gitalk.json"
},
{
"$ref": "/comment/gitment.json"
},
{
"$ref": "/comment/isso.json"
},
{
"$ref": "/comment/livere.json"
},
{
"$ref": "/comment/utterances.json"
},
{
"$ref": "/comment/valine.json"
},
{
"$ref": "/comment/waline.json"
},
{
"$ref": "/comment/twikoo.json"
}
]
}
================================================
FILE: include/schema/common/donates.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/donates.json",
"description": "Donate plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/",
"type": "array",
"items": {
"type": "object",
"oneOf": [
{
"$ref": "/donate/afdian.json"
},
{
"$ref": "/donate/alipay.json"
},
{
"$ref": "/donate/buymeacoffee.json"
},
{
"$ref": "/donate/patreon.json"
},
{
"$ref": "/donate/paypal.json"
},
{
"$ref": "/donate/wechat.json"
}
]
}
}
================================================
FILE: include/schema/common/footer.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/footer.json",
"description": "Page footer configurations",
"type": "object",
"properties": {
"copyright": {
"description": "Copyright text",
"type": "string",
"examples": [
"© 2019",
"© 2019 - 2020",
"© 2019 - 2020, Company Name",
"© 2019 - 2020, Company Name. All rights reserved.",
"粤ICP备12345678号"
]
},
"links": {
"$ref": "/misc/poly_links.json",
"description": "Links to be shown on the right of the footer section",
"examples": [
{
"Creative Commons": {
"icon": "fab fa-creative-commons",
"url": "https://creativecommons.org/"
},
"Attribution 4.0 International": {
"icon": "fab fa-creative-commons-by",
"url": "https://creativecommons.org/licenses/by/4.0/"
},
"Download on GitHub": {
"icon": "fab fa-github",
"url": "https://github.com/ppoffice/hexo-theme-icarus"
}
}
]
}
}
}
================================================
FILE: include/schema/common/head.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/head.json",
"description": "Page metadata configurations",
"type": "object",
"properties": {
"favicon": {
"type": "string",
"description": "URL or path to the website's icon",
"default": "/img/favicon.svg",
"nullable": true
},
"manifest": {
"$ref": "/misc/manifest.json"
},
"open_graph": {
"$ref": "/misc/open_graph.json"
},
"structured_data": {
"$ref": "/misc/structured_data.json"
},
"meta": {
"$ref": "/misc/meta.json"
},
"rss": {
"type": "string",
"description": "URL or path to the website's RSS atom.xml",
"nullable": true
}
}
}
================================================
FILE: include/schema/common/navbar.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/navbar.json",
"description": "Page top navigation bar configurations",
"type": "object",
"properties": {
"menu": {
"type": "object",
"description": "Navigation menu items",
"patternProperties": {
".+": {
"type": "string",
"description": "URL or path of the menu link"
}
},
"examples": [
{
"Home": "/",
"Archives": "/archives",
"Categories": "/categories",
"Tags": "/tags",
"About": "/about"
}
],
"nullable": true
},
"links": {
"$ref": "/misc/poly_links.json",
"description": "Links to be shown on the right of the navigation bar",
"examples": [
{
"Download on GitHub": {
"icon": "fab fa-github",
"url": "https://github.com/ppoffice/hexo-theme-icarus"
}
}
]
}
}
}
================================================
FILE: include/schema/common/plugins.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/plugins.json",
"description": "Plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/",
"type": "object",
"properties": {
"animejs": {
"$ref": "/plugin/animejs.json"
},
"back_to_top": {
"$ref": "/plugin/back_to_top.json"
},
"baidu_analytics": {
"$ref": "/plugin/baidu_analytics.json"
},
"bing_webmaster": {
"$ref": "/plugin/bing_webmaster.json"
},
"busuanzi": {
"$ref": "/plugin/busuanzi.json"
},
"cnzz": {
"$ref": "/plugin/cnzz.json"
},
"cookie_consent": {
"$ref": "/plugin/cookie_consent.json"
},
"gallery": {
"$ref": "/plugin/gallery.json"
},
"google_analytics": {
"$ref": "/plugin/google_analytics.json"
},
"hotjar": {
"$ref": "/plugin/hotjar.json"
},
"katex": {
"$ref": "/plugin/katex.json"
},
"mathjax": {
"$ref": "/plugin/mathjax.json"
},
"outdated_browser": {
"$ref": "/plugin/outdated_browser.json"
},
"pjax": {
"$ref": "/plugin/pjax.json"
},
"progressbar": {
"$ref": "/plugin/progressbar.json"
},
"statcounter": {
"$ref": "/plugin/statcounter.json"
},
"twitter_conversion_tracking": {
"$ref": "/plugin/twitter_conversion_tracking.json"
}
}
}
================================================
FILE: include/schema/common/providers.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/providers.json",
"description": "CDN provider settings\nhttps://ppoffice.github.io/hexo-theme-icarus/Configuration/Theme/speed-up-your-site-with-custom-cdn/",
"type": "object",
"properties": {
"cdn": {
"type": "string",
"description": "Name or URL template of the JavaScript and/or stylesheet CDN provider",
"default": "jsdelivr",
"nullable": true
},
"fontcdn": {
"type": "string",
"description": "Name or URL template of the webfont CDN provider",
"default": "google",
"nullable": true
},
"iconcdn": {
"type": "string",
"description": "Name or URL of the fontawesome icon font CDN provider",
"default": "fontawesome",
"nullable": true
}
}
}
================================================
FILE: include/schema/common/search.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/search.json",
"description": "Search plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Search/",
"type": "object",
"oneOf": [
{
"$ref": "/search/insight.json"
},
{
"$ref": "/search/baidu.json"
},
{
"$ref": "/search/google_cse.json"
},
{
"$ref": "/search/algolia.json"
}
]
}
================================================
FILE: include/schema/common/share.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/share.json",
"description": "Share plugin configurations\nhttps://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/",
"type": "object",
"oneOf": [
{
"$ref": "/share/sharethis.json"
},
{
"$ref": "/share/addthis.json"
},
{
"$ref": "/share/addtoany.json"
},
{
"$ref": "/share/bdshare.json"
},
{
"$ref": "/share/sharejs.json"
}
]
}
================================================
FILE: include/schema/common/sidebar.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/sidebar.json",
"description": "Sidebar configurations.\nPlease be noted that a sidebar is only visible when it has at least one widget",
"type": "object",
"properties": {
"left": {
"type": "object",
"description": "Left sidebar configurations",
"properties": {
"sticky": {
"type": "boolean",
"description": "Whether the sidebar sticks to the top when page scrolls",
"default": false
}
}
},
"right": {
"type": "object",
"description": "Right sidebar configurations",
"properties": {
"sticky": {
"type": "boolean",
"description": "Whether the sidebar sticks to the top when page scrolls",
"default": false
}
}
}
}
}
================================================
FILE: include/schema/common/widgets.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/common/widgets.json",
"description": "Sidebar widget configurations\nhttp://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/",
"type": "array",
"items": {
"type": "object",
"properties": {
"position": {
"type": "string",
"description": "Where should the widget be placed, left sidebar or right sidebar",
"default": "left"
}
},
"oneOf": [
{
"$ref": "/widget/profile.json"
},
{
"$ref": "/widget/toc.json"
},
{
"$ref": "/widget/links.json"
},
{
"$ref": "/widget/categories.json"
},
{
"$ref": "/widget/recent_posts.json"
},
{
"$ref": "/widget/archives.json"
},
{
"$ref": "/widget/tags.json"
},
{
"$ref": "/widget/subscribe_email.json"
},
{
"$ref": "/widget/adsense.json"
},
{
"$ref": "/widget/followit.json"
}
],
"required": [
"position"
]
}
}
================================================
FILE: include/schema/config.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/config.json",
"description": "The configuration file definition",
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "Version of the configuration file",
"default": "5.1.0"
},
"variant": {
"type": "string",
"description": "Icarus theme variant, can be \"default\" or \"cyberpunk\"",
"enum": [
"default",
"cyberpunk"
],
"default": "default"
},
"logo": {
"type": [
"string",
"object"
],
"description": "Path or URL to the website's logo",
"default": "/img/logo.svg",
"properties": {
"text": {
"type": "string",
"description": "Text to be shown in place of the logo image"
}
},
"required": [
"text"
]
},
"head": {
"$ref": "/common/head.json"
},
"navbar": {
"$ref": "/common/navbar.json"
},
"footer": {
"$ref": "/common/footer.json"
},
"article": {
"$ref": "/common/article.json"
},
"search": {
"$ref": "/common/search.json"
},
"comment": {
"$ref": "/common/comment.json"
},
"donates": {
"$ref": "/common/donates.json"
},
"share": {
"$ref": "/common/share.json"
},
"sidebar": {
"$ref": "/common/sidebar.json"
},
"widgets": {
"$ref": "/common/widgets.json"
},
"plugins": {
"$ref": "/common/plugins.json"
},
"providers": {
"$ref": "/common/providers.json"
}
},
"required": [
"version"
]
}
================================================
FILE: include/schema/donate/.gitkeep
================================================
================================================
FILE: include/schema/misc/.gitkeep
================================================
================================================
FILE: include/schema/plugin/animejs.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/plugin/animejs.json",
"description": "Enable page startup animations",
"type": "boolean",
"default": true
}
================================================
FILE: include/schema/plugin/back_to_top.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/plugin/back_to_top.json",
"description": "Show the \"back to top\" button",
"type": "boolean",
"default": true
}
================================================
FILE: include/schema/plugin/pjax.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/plugin/pjax.json",
"description": "Enable PJAX",
"type": "boolean",
"default": true
}
================================================
FILE: include/schema/search/.gitkeep
================================================
================================================
FILE: include/schema/share/.gitkeep
================================================
================================================
FILE: include/schema/widget/profile.json
================================================
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "/widget/profile.json",
"description": "Profile widget configurations",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "profile",
"nullable": true
},
"author": {
"type": "string",
"description": "Author name",
"examples": [
"Your name"
],
"nullable": true
},
"author_title": {
"type": "string",
"description": "Author title",
"examples": [
"Your title"
],
"nullable": true
},
"location": {
"type": "string",
"description": "Author's current location",
"examples": [
"Your location"
],
"nullable": true
},
"avatar": {
"type": "string",
"description": "URL or path to the avatar image",
"nullable": true
},
"avatar_rounded": {
"type": "boolean",
"description": "Whether show the rounded avatar image",
"default": false,
"nullable": true
},
"gravatar": {
"type": "string",
"description": "Email address for the Gravatar",
"nullable": true
},
"follow_link": {
"type": "string",
"description": "URL or path for the follow button",
"examples": [
"https://github.com/ppoffice"
],
"nullable": true
},
"social_links": {
"$ref": "/misc/poly_links.json",
"description": "Links to be shown on the bottom of the profile widget",
"examples": [
{
"Github": {
"icon": "fab fa-github",
"url": "https://github.com/ppoffice"
},
"Facebook": {
"icon": "fab fa-facebook",
"url": "https://facebook.com"
},
"Twitter": {
"icon": "fab fa-twitter",
"url": "https://twitter.com"
},
"Dribbble": {
"icon": "fab fa-dribbble",
"url": "https://dribbble.com"
},
"RSS": {
"icon": "fas fa-rss",
"url": "/"
}
}
]
}
},
"required": [
"type"
]
}
================================================
FILE: include/style/article.styl
================================================
/* ---------------------------------
* Article Summary and Content
* --------------------------------- */
$article-font-size ?= 1.1rem
article
&.media
color: $text-light
a
color: inherit
&:hover
color: $primary
.image
width: 64px
height: 64px
img
object-fit: cover
width: 100%
height: 100%
.title
@extend .is-size-6
margin-bottom: .25em
.date, .categories
@extend .is-size-7
.categories
@extend .is-uppercase
.media-content
color: $text-light
.title
margin: 0
line-height: inherit
&.article
.article-meta, .article-tags
color: $text-light
.article-meta
overflow-x: auto
margin-bottom: .5rem
.article-more
@extend .button.is-light
.content
word-wrap: break-word
font-size: $article-font-size
h1
font-size: 1.75em
h2
font-size: 1.5em
h3
font-size: 1.25em
h4
font-size: 1.125em
h5
font-size: 1em
pre
font-size: .85em
code
padding: 0
background: transparent
overflow-wrap: break-word
blockquote
&.pullquote
float: right
max-width: 50%
font-size: 1.15rem
position: relative
footer
strong + cite
margin-left: .5em
.message.message-immersive
border-radius: 0
margin: 0 0 - $card-content-padding $card-content-padding 0 - $card-content-padding
.message-body
border: none
.article-tags
display: flex
flex-wrap: wrap
.rtl
direction: rtl
.level
&, &.is-mobile
.level-item:not(:last-child)
margin-left: .75rem
margin-right: 0
// Overflow table
.table-overflow
overflow-x: auto
table
width: auto !important
th
word-break: keep-all
// Video container
.video-container
position: relative
padding-bottom: 56.25%
padding-top: 25px
height: 0
iframe
position: absolute
top: 0
left: 0
width: 100%
height: 100%
.article-licensing
position: relative
z-index: 1
box-shadow: none
background: $white-ter
border-radius: $radius
overflow: hidden
&:after
position: absolute
z-index: -1
right: -50px
top: -87.87px
content: '\f25e'
font-size: 200px
font-family: 'Font Awesome 5 Brands'
opacity: .1
.level-left
flex-wrap: wrap
max-width: 100%
.licensing-title
@extend .mb-3
line-height: 1.2
p:not(:last-child)
@extend .mb-1
a
@extend .is-size-7, .has-text-grey
.licensing-meta
.level-item
@extend .mr-4
.icons
.icon
@extend .ml-1
width: 1.2em
height: 1.2em
font-size: 1.2em
vertical-align: bottom
h6
@extend .is-size-7
a
color: inherit
a
&.article-nav-prev
span
text-align: left
flex-shrink: 1
word-wrap: break-word
white-space: normal
&.article-nav-next
span
text-align: right
flex-shrink: 1
word-wrap: break-word
white-space: normal
================================================
FILE: include/style/base.styl
================================================
bulma-stylus-root = '../../../../node_modules/bulma-stylus/stylus'
/* ---------------------------------
* Override Bulma CSS Framework
* --------------------------------- */
$body-size ?= 14px
$body-background-color ?= #f7f7f7
$family-sans-serif ?= Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif
$family-code ?= 'Source Code Pro', monospace, 'Microsoft YaHei'
$size-7 ?= .85rem
$size-small ?= .75rem
$primary ?= $blue
$custom-colors ?= {
grey-lightest: {
'1': $grey-lightest
'2': $grey-darker
}
}
$navbar-item-active-color ?= $primary
$footer-background-color ?= $scheme-main
$gap ?= 64px
$tablet ?= 769px
$desktop ?= 1088px
$widescreen ?= 1280px
$fullhd ?= 1472px
$shadow ?= 0 4px 10px rgba(0, 0, 0, 0.05)
$title-weight ?= $weight-normal
$control-height ?= 2.25em
$button-padding-vertical ?= calc(0.375em - 1px)
$card-radius ?= $radius
$card-media-margin ?= 0.75rem
$card-shadow ?= $shadow, 0 0 1px rgba(0, 0, 0, 0.1)
$menu-item-active-color ?= $link
$menu-item-active-background-color ?= hsl(219, 70%, 96%)
$content-heading-weight ?= $weight-normal
$logo-height ?= 1.75rem
// FIXME: https://github.com/groenroos/bulma-stylus/issues/11
@import bulma-stylus-root + '/utilities/initial-variables'
@import bulma-stylus-root + '/utilities/functions'
@import bulma-stylus-root + '/utilities/derived-variables'
$colors = merge($colors, $custom-colors)
@import bulma-stylus-root + '/utilities/animations'
@import bulma-stylus-root + '/utilities/mixins'
@import bulma-stylus-root + '/utilities/controls'
@import bulma-stylus-root + '/base/_all'
@import bulma-stylus-root + '/components/_all'
@import bulma-stylus-root + '/elements/_all'
@import bulma-stylus-root + '/form/_all'
@import bulma-stylus-root + '/grid/_all'
@import bulma-stylus-root + '/layout/_all'
html
height: 100%
-webkit-text-size-adjust: 100%
-moz-text-size-adjust: 100%
-ms-text-size-adjust: 100%
text-size-adjust: 100%
body
min-height: 100%
display: flex
flex-direction: column
body > .section
flex-grow: 1
+desktop()
::-webkit-scrollbar
width: 8px
height: 8px
::-webkit-scrollbar-track
border-radius: 3px
background: rgba(0,0,0,0.06)
box-shadow: inset 0 0 5px rgba(0,0,0,0.1)
::-webkit-scrollbar-thumb
border-radius: 3px
background: rgba(0,0,0,0.12)
box-shadow: inset 0 0 10px rgba(0,0,0,0.2)
::-webkit-scrollbar-thumb:hover
background: rgba(0,0,0,0.24)
================================================
FILE: include/style/button.styl
================================================
/* ---------------------------------
* Buttons
* --------------------------------- */
.button
&.is-transparent
color: inherit
background: transparent
border-color: transparent
================================================
FILE: include/style/card.styl
================================================
/* ---------------------------------
* Card
* --------------------------------- */
.card
overflow: visible
border-radius: $card-radius
& + .card, & + .column-right-shadow
margin-top: 1.5rem
.card-image
overflow: hidden
border-top-left-radius: $card-radius
border-top-right-radius: $card-radius
.media + .media
border: none
margin-top: 0
================================================
FILE: include/style/codeblock.styl
================================================
/* ---------------------------------
* Code Highlight
* --------------------------------- */
$codeblock-caption-bg ?= rgba(200, 200, 200, .15)
figure.highlight
padding: 0
width: 100%
position: relative
margin: 1em 0 1em !important
border-radius: $radius
&.folded
.highlight-body
height: 0
.copy
opacity: .7
pre, table tr:hover
color: inherit
background: transparent
table
width: auto
tr td
border: none
tr:not(:first-child) td
padding-top: 0
tr:not(:last-child) td
padding-bottom: 0
pre
padding: 0
overflow: visible
.line, code .hljs
line-height: 1.5rem
figcaption, .gutter
background: $codeblock-caption-bg
figcaption
margin: 0 !important
padding: .3em 0em .3em .75em
font-style: normal
font-size: .8em
*
color: inherit
span
font-weight: 500
font-family: $family-code
.level-left *:not(:last-child)
margin-right: .5em
.level-right *:not(:first-child)
margin-left: .5em
.fold
cursor: pointer
&.level
overflow: auto
.level-right
a
padding: 0em .75em
.highlight-body
overflow: auto
.gutter
text-align: right
.tag, .title, .number, .section
display: inherit
font: inherit
margin: inherit
padding: inherit
background: inherit
height: inherit
text-align: inherit
vertical-align: inherit
min-width: inherit
border-radius: inherit
figure.highlight.foldable
div.level-left
cursor: pointer // clicking the codeblock filename can toggle folding
/* ---------------------------------
* Fix Gist Snippet
* --------------------------------- */
.gist
table
tr:hover
background: transparent
td
border: none
.file
all: initial
================================================
FILE: include/style/donate.styl
================================================
/* ---------------------------------
* Donate Buttons
* --------------------------------- */
$donate-qrcode-max-width ?= 280px
$donate-qrcode-shadow ?= $card-shadow
$donate-qrcode-box-radius ?= $card-radius
$donate-button-colors ?= {
'afdian': rgb(136, 95, 217),
'alipay': rgb(0, 160, 232),
'buymeacoffee': rgb(255, 221, 0),
'paypal': rgb(254, 183, 0),
'patreon': rgb(255, 66, 77),
'wechat': rgb(26, 173, 25),
}
.donate
position: relative
.qrcode
display: none
position: absolute
z-index: 99
bottom: 2.5em
line-height: 0
overflow: hidden
box-shadow: $donate-qrcode-shadow
border-radius: $donate-qrcode-box-radius
img
max-width: $donate-qrcode-max-width
&:hover
.qrcode
display: block
&:first-child:not(:last-child)
.qrcode
left: -.75rem
&:last-child:not(:first-child)
.qrcode
right: -.75rem
for $name, $color in $donate-button-colors
&[data-type={'"' + $name + '"'}]
color: findColorInvert($color)
background-color: $color
border-color: transparent
&:active
background-color: darken($color, 5%)
&:hover
background-color: darken($color, 2.5%)
&:focus:not(:active)
box-shadow: 0 0 0 .125em rgba($color, .25)
================================================
FILE: include/style/footer.styl
================================================
/* ---------------------------------
* Page Footer
* --------------------------------- */
footer.footer
.level-start
+mobile()
text-align: center
.level-end
.field
flex-wrap: wrap
align-items: center
+mobile()
justify-content: center
margin-top: 1rem
.footer-logo
img
max-height: $logo-height
================================================
FILE: include/style/helper.styl
================================================
/* ---------------------------------
* Spacing helpers
* --------------------------------- */
$spacer ?= 1rem
$spacers ?= 0, $spacer * .25, $spacer * .5, $spacer, $spacer * 1.5, $spacer * 3
for n in (0 .. 5)
.ml-{n}
margin-left: $spacers[n] !important
.mr-{n}
margin-right: $spacers[n] !important
.mx-{n}
@extend .ml-{n}, .mr-{n}
.ml-n{n}
margin-left: - $spacers[n] !important
.mr-n{n}
margin-right: - $spacers[n] !important
.mx-n{n}
@extend .ml-n{n}, .mr-n{n}
.mt-{n}
margin-top: $spacers[n] !important
.mb-{n}
margin-bottom: $spacers[n] !important
.my-{n}
@extend .mt-{n}, .mb-{n}
.mt-n{n}
margin-top: - $spacers[n] !important
.mb-n{n}
margin-bottom: - $spacers[n] !important
.my-n{n}
@extend .mt-n{n}, .mb-n{n}
.pl-{n}
padding-left: $spacers[n] !important
.pr-{n}
padding-right: $spacers[n] !important
.px-{n}
@extend .pl-{n}, .pr-{n}
.pl-n{n}
padding-left: - $spacers[n] !important
.pr-n{n}
padding-right: - $spacers[n] !important
.px-n{n}
@extend .pl-n{n}, .pr-n{n}
.pt-{n}
padding-top: $spacers[n] !important
.pb-{n}
padding-bottom: $spacers[n] !important
.py-{n}
@extend .pt-{n}, .pb-{n}
.pt-n{n}
padding-top: - $spacers[n] !important
.pb-n{n}
padding-bottom: - $spacers[n] !important
.py-n{n}
@extend .pt-n{n}, .pb-n{n}
.ml-auto
margin-left: auto !important
.mr-auto
margin-right: auto !important
.mx-auto
@extend .ml-auto, .mr-auto
.mt-auto
margin-top: auto !important
.mb-auto
margin-bottom: auto !important
.my-auto
@extend .mt-auto, .mb-auto
.pl-auto
margin-left: auto !important
.pr-auto
margin-right: auto !important
.px-auto
@extend .pl-auto, .pr-auto
.pt-auto
margin-top: auto !important
.pb-auto
margin-bottom: auto !important
.py-auto
@extend .pt-auto, .pb-auto
/* ---------------------------------
* Flex helpers
* --------------------------------- */
for n in (0 .. 5)
.order-{n}
order: n !important
.justify-content-start
justify-content: start !important
.justify-content-center
justify-content: center !important
.flex-shrink-1
flex-shrink: 1 !important
/* ---------------------------------
* Color helpers
* --------------------------------- */
.link-muted
color: inherit
&:hover
color: $primary !important
/* ---------------------------------
* Image helpers
* --------------------------------- */
.image
&.is-7by3
padding-top: 42.8%
img
bottom: 0
left: 0
position: absolute
right: 0
top: 0
.avatar
height: 100%
object-fit: cover
.fill
object-fit: cover
width: 100% !important
height: 100% !important
================================================
FILE: include/style/navbar.styl
================================================
/* ---------------------------------
* Top Navigation
* --------------------------------- */
$navbar-item-padding-v ?= 1.25rem
$navbar-item-padding-h ?= .75rem
$navbar-item-margin-v ?= 0
$navbar-item-margin-h ?= 0
.navbar-main
box-shadow: $shadow
.navbar-container
overflow-x: auto
.navbar-menu, .navbar-start, .navbar-end
align-items: stretch
display: flex
padding: 0
flex-shrink: 0
.navbar-menu
flex-grow: 1
flex-shrink: 0
overflow-x: auto
.navbar-start
justify-content: flex-start
margin-right: auto
.navbar-end
justify-content: flex-end
margin-left: auto
.navbar-item
display: flex
align-items: center
padding: $navbar-item-padding-v $navbar-item-padding-h
margin: $navbar-item-margin-v $navbar-item-margin-h
&.is-active
background-color: transparent
+until($navbar-breakpoint)
.navbar-menu
justify-content: center
box-shadow: none
.navbar-start
margin-right: 0
.navbar-end
margin-left: 0
.navbar-logo
img
max-height: $logo-height
@media screen and (min-width: $desktop)
.navbar > .container .navbar-menu, .container > .navbar .navbar-menu
margin-right: 0rem
================================================
FILE: include/style/pagination.styl
================================================
/* ---------------------------------
* Pagination and Post Navigation
* --------------------------------- */
$pagination-box-shadow ?= $card-shadow
$pagination-background-color ?= $button-background-color
$post-navigation-fg ?= $grey
.pagination
@extend .pagination.is-centered
margin-top: 1.5rem
.pagination-link,
.pagination-ellipsis,
.pagination-previous,
.pagination-next
a
color: $pagination-color
.pagination-link,
.pagination-previous,
.pagination-next
border: none
background: $pagination-background-color
box-shadow: $pagination-box-shadow
.pagination-link.is-current
background: $pagination-current-background-color
.post-navigation
color: $post-navigation-fg
flex-wrap: wrap
justify-content: space-around
.level-item
margin-bottom: 0
================================================
FILE: include/style/plugin.styl
================================================
/* ---------------------------------
* Back to Top Button
* --------------------------------- */
#back-to-top
position: fixed
opacity: 0
outline: none
padding: 8px 0
line-height: 24px
border-radius: $card-radius
transform: translateY(120px)
transition: .4s ease opacity, .4s ease width, .4s ease transform, .4s ease border-radius
&.is-rounded
border-radius: 50%
&.fade-in
opacity: 1
&.rise-up
transform: translateY(0)
/* ---------------------------------
* Gallery Plugin
* --------------------------------- */
.gallery-item
.caption
color: $grey
/* ---------------------------------
* Page Loading Progressbar
* --------------------------------- */
.pace
user-select: none
pointer-events: none
.pace-progress
top: 0
right: 100%
width: 100%
height: 2px
z-index: 2000
position: fixed
background: $primary
.pace-inactive
display: none
/* ---------------------------------
* Fix FontAwesome Icons
* --------------------------------- */
.fa, .fab, .fal, .far, .fas
line-height: inherit
/* ---------------------------------
* MathJax and KaTeX
* --------------------------------- */
.MathJax, .MathJax_Display, .MJXc-display, .MathJax_SVG_Display, .katex-display
overflow-x: auto
overflow-y: hidden
.katex
white-space: nowrap
.katex-display
margin-top: -1em !important
.katex-html
padding-top: 1em
.tag
align-items: unset
background-color: unset
border-radius: unset
color: unset
display: unset
font-size: unset
height: unset
justify-content: unset
line-height: unset
padding-left: unset
padding-right: unset
white-space: unset
/* ---------------------------------
* Cookie Consent
* --------------------------------- */
.cc-window, .cc-revoke
font-size: 1.1rem !important
font-family: $family-sans-serif !important
.cc-window
color: $text !important
background-color: $scheme-main !important
&.cc-floating
border-radius: $card-radius
box-shadow: $card-shadow
&.cc-banner
background-color: darken($scheme-main, 2.5%) !important
&.cc-theme-block, &.cc-theme-classic
.cc-compliance > .cc-btn
border-radius: $radius-rounded
.cc-compliance > .cc-btn
font-weight: 400
border: none
color: $primary-invert
background-color: $primary
&:hover, &:focus
background-color: darken($primary, 2.5%)
&.cc-deny
&:hover
color: $primary
text-decoration: none
.cc-revoke
padding: .5rem 1rem !important
color: $primary-invert !important
background-color: $primary !important
&:hover
text-decoration: none !important
background-color: darken($primary, 2.5%)
================================================
FILE: include/style/responsive.styl
================================================
/* ---------------------------------
* Responsive Layout
* --------------------------------- */
+widescreen()
.is-1-column .container, .is-2-column .container
max-width: $desktop - 2 * $gap
width: $desktop - 2 * $gap
+fullhd()
.is-2-column .container
max-width: $widescreen - 2 * $gap
width: $widescreen - 2 * $gap
.is-1-column .container
max-width: $desktop - 2 * $gap
width: $desktop - 2 * $gap
+tablet()
.is-sticky
position: -webkit-sticky
position: sticky
top: 1.5rem
z-index: 99
.column-main, .column-left, .column-right, .column-right-shadow
&.is-sticky
top: .75rem
align-self: flex-start
+mobile()
.section
padding: 1.5rem 1rem
================================================
FILE: include/style/search.styl
================================================
/* ---------------------------------
* Search Box
* --------------------------------- */
// container sizes
$searchbox-container-width ?= 540px
$searchbox-container-margin ?= 100px
$searchbox-breakpoint-width ?= 559px
$searchbox-breakpoint-height ?= 479px
// overlay and container styles
$searchbox-box-shadow ?= $card-shadow
$searchbox-border-radius ?= $radius
$searchbox-bg-overlay ?= $modal-background-background-color
$searchbox-bg-container ?= $white-ter
$searchbox-border ?= $border
// header styles
$searchbox-bg-input ?= $white
$searchbox-bg-close-hover ?= $searchbox-bg-container
$searchbox-bg-close-active ?= $grey-lighter
// body styles
$searchbox-fg-result-header ?= $grey-light
$searchbox-fg-result-item-secondary ?= $grey-light
$searchbox-bg-result-item-hover ?= $searchbox-bg-input
$searchbox-fg-result-item-active ?= findColorInvert($primary)
$searchbox-bg-result-item-active ?= $primary
$searchbox-bg-result-item-highlight ?= $yellow
// footer styles
$searchbox-bg-pagination-item ?= $searchbox-bg-input
$searchbox-bg-pagination-item-hover ?= $searchbox-bg-container
$searchbox-fg-pagination-item-active ?= findColorInvert($primary)
$searchbox-bg-pagination-item-active ?= $primary
$searchbox-bg-pagination-item-disabled ?= $searchbox-bg-container
.searchbox
display: none
top: 0
left: 0
width: 100%
height: 100%
z-index: 100
font-size: 1rem
line-height: 0
background: $searchbox-bg-overlay
&.show
display: flex
a, a:hover
color: inherit
text-decoration: none
input
font-size: 1rem
border: none
outline: none
box-shadow: none
border-radius: 0
&, .searchbox-container
position: fixed
align-items: center
flex-direction: column
line-height: 1.25em
.searchbox-container
z-index: 101
display: flex
overflow: hidden
box-shadow: $searchbox-box-shadow
border-radius: $searchbox-border-radius
background-color: $searchbox-bg-container
width: $searchbox-container-width
top: $searchbox-container-margin
bottom: $searchbox-container-margin
.searchbox-header, .searchbox-body, .searchbox-footer
width: 100%
.searchbox-header
display: flex
flex-direction: row
line-height: 1.5em
font-weight: normal
background-color: $searchbox-bg-input
// fix Chrome 71 height issue
// https://github.com/ppoffice/hexo-theme-icarus/issues/719
min-height: 3rem
.searchbox-input-container
display: flex
flex-grow: 1
.searchbox-input
flex-grow: 1
color: inherit
box-sizing: border-box
padding: .75em 0 .75em 1.25em
background: $searchbox-bg-input
.searchbox-close
display: inline-block
font-size: 1.5em
padding: .5em .75em
cursor: pointer
&:hover
background: $searchbox-bg-close-hover
&:active
background: $searchbox-bg-close-active
.searchbox-body
flex-grow: 1
overflow-y: auto
border-top: 1px solid $searchbox-border
.searchbox-result-section header, .searchbox-result-item
padding: .75em 1em
.searchbox-result-section
border-bottom: 1px solid $searchbox-border
header
color: $searchbox-fg-result-header
.searchbox-result-item
display: flex
flex-direction: row
&:not(.disabled):not(.active):not(:active):hover
background-color: $searchbox-bg-result-item-hover
&:active, &.active
color: $searchbox-fg-result-item-active
background-color: $searchbox-bg-result-item-active
em
font-style: normal
background: $searchbox-bg-result-item-highlight
.searchbox-result-icon
margin-right: 1em
.searchbox-result-content
overflow: hidden
.searchbox-result-title, .searchbox-result-preview
display: block
overflow: hidden
white-space: nowrap
text-overflow: ellipsis
.searchbox-result-title-secondary
color: $searchbox-fg-result-item-secondary
.searchbox-result-preview
margin-top: .25em
.searchbox-result-item:not(:active):not(.active)
.searchbox-result-preview
color: $searchbox-fg-result-item-secondary
.searchbox-footer
padding: .5em 1em
.searchbox-pagination
margin: 0
padding: 0
list-style: none
text-align: center
.searchbox-pagination-item
margin: 0 .25rem
.searchbox-pagination-item, .searchbox-pagination-link
display: inline-block
.searchbox-pagination-link
overflow: hidden
padding: .5em .8em
box-shadow: $searchbox-box-shadow
border-radius: $searchbox-border-radius
background-color: $searchbox-bg-pagination-item
.searchbox-pagination-item.active
.searchbox-pagination-link
color: $searchbox-fg-pagination-item-active
background-color: $searchbox-bg-pagination-item-active
.searchbox-pagination-item.disabled
.searchbox-pagination-link
cursor: not-allowed
background-color: $searchbox-bg-pagination-item-disabled
.searchbox-pagination-item:not(.active):not(.disabled)
.searchbox-pagination-link:hover
background-color: $searchbox-bg-pagination-item-hover
@media screen and (max-width: $searchbox-breakpoint-width), screen and (max-height: $searchbox-breakpoint-height)
.searchbox .searchbox-container
top: 0
left: 0
width: 100%
height: 100%
border-radius: 0
================================================
FILE: include/style/timeline.styl
================================================
/* ---------------------------------
* Archive Timeline
* --------------------------------- */
$timeline-fg-line ?= $grey-lighter
$timeline-bg-line ?= $card-background-color
.timeline
margin-left: 1rem
padding: 1rem 0 0 1.5rem
border-left: 1px solid $timeline-fg-line
.media
position: relative
&:before, &:last-child:after
content: ''
display: block
position: absolute
left: calc(-.375rem - 1.5rem - .25px)
&:before
width: .75rem
height: .75rem
top: calc(1rem + 1.5 * .85rem / 2 - .75rem / 2)
background: $timeline-fg-line
border-radius: 50%
&:first-child:before
top: calc(1.5 * .85rem / 2 - .75rem / 2)
&:last-child:after
width: .75rem
top: calc(1rem + 1.5 * .85rem / 2 + .75rem / 2)
bottom: 0
background: $timeline-bg-line
&:first-child:last-child:after
top: calc(1.5 * .85rem / 2 + .75rem / 2)
================================================
FILE: include/style/widget.styl
================================================
.widget
.menu-list
li
ul
margin-right: 0
.level
margin-bottom: 0
.level-left, .level-right, .level-item
flex-shrink: 1
.level-left, .level-right
align-items: flex-start
.tag
background: $light-grey
color: $white-invert
.tags
.tag:first-child
background: $primary
color: $primary-invert
.tag:last-child
background: $light-grey
color: $white-invert
.level.is-multiline
flex-wrap: wrap
/* ---------------------------------
* Table of Content Widget
* --------------------------------- */
+mobile()
.widget.card#toc
display: none
position: fixed
margin: 1rem
left: 0
right: 0
bottom: 0
z-index: 100
.card-content
padding: 0
.menu
padding: 1.5rem
max-height: calc(100vh - 2rem)
overflow-y: auto
#toc-mask
display: none
position: fixed
top: 0
left: 0
right: 0
bottom: 0
z-index: 99
background: rgba(0, 0, 0, .7)
.widget.card#toc, #toc-mask
&.is-active
display: block
================================================
FILE: include/util/console.js
================================================
let chalk;
try {
chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require
} catch (e) { }
module.exports = new Proxy({}, {
get(obj, prop) {
if (chalk) {
return chalk[prop];
}
return function() {
return arguments.length === 1 ? arguments[0] : arguments;
};
}
});
================================================
FILE: languages/de.yml
================================================
common:
archive:
one: 'Archiv'
other: 'Archive'
category:
one: 'Kategorie'
other: 'Kategorien'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Seite'
other: 'Seiten'
page:
one: 'Page'
other: 'Pages'
prev: 'Zurück'
next: 'Weiter'
widget:
follow: 'Folgen'
recents: 'Letzte Einträge'
links: 'Links'
catalogue: 'Katalog'
subscribe_email: 'Abonnieren Sie Updates'
subscribe: 'Abonnieren'
adsense: 'Werbung'
followit: 'follow.it'
article:
created_at: 'Gepostet vor %s'
updated_at: 'Aktualisiert vor %s'
more: 'Mehr lesen'
comments: 'Kommentare'
read_time: '%s lesen'
word_count:
one: 'Über %d Wort'
other: 'Über %d Wörter'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Gefällt Ihnen der Artikel? Unterstützen Sie den Autor mit'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Kauf mir einen Kaffee'
plugin:
backtotop: 'Zurück nach oben'
visit_count: '%s Besuche'
visitor_count: 'Von %s Nutzern besucht'
cookie_consent:
message: Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern.
dismiss: Verstanden!
allow: Cookies zulassen
deny: Ablehnen
link: Mehr erfahren
policy: Cookie-Richtlinie
search:
search: 'Suche'
hint: 'Tippen Sie etwas...'
no_result: 'Keine Ergebnisse für'
untitled: '(Ohne Titel)'
empty_preview: '(Keine Vorschau)'
================================================
FILE: languages/en.yml
================================================
common:
archive:
one: 'Archive'
other: 'Archives'
category:
one: 'Category'
other: 'Categories'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Post'
other: 'Posts'
page:
one: 'Page'
other: 'Pages'
prev: 'Previous'
next: 'Next'
widget:
follow: 'Follow'
recents: 'Recents'
links: 'Links'
catalogue: 'Catalogue'
subscribe_email: 'Subscribe for updates'
subscribe: 'Subscribe'
adsense: 'Advertisement'
followit: 'follow.it'
article:
created_at: 'Posted %s'
updated_at: 'Updated %s'
more: 'Read more'
comments: 'Comments'
read_time: '%s read'
word_count:
one: 'About %d word'
other: 'About %d words'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Like this article? Support the author with'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Buy me a coffee'
plugin:
backtotop: 'Back to top'
visit_count: '%s visits'
visitor_count: 'Visited by %s users'
cookie_consent:
message: This website uses cookies to improve your experience.
dismiss: Got it!
allow: Allow cookies
deny: Decline
link: Learn more
policy: Cookie Policy
search:
search: 'Search'
hint: 'Type something...'
no_result: 'No results for'
untitled: '(Untitled)'
empty_preview: '(No preview)'
================================================
FILE: languages/es.yml
================================================
#By SrWoOoW
common:
archive:
one: 'Archivo'
other: 'Archivos'
category:
one: 'Categoría'
other: 'Categorías'
tag:
one: 'Etiqueta'
other: 'Etiquetas'
post:
one: 'Entrada'
other: 'Entradas'
page:
one: 'Página'
other: 'Páginas'
prev: 'Anterior'
next: 'Siguiente'
widget:
follow: 'SEGUIR'
recents: 'Recientes'
links: 'Enlaces'
catalogue: 'Catálogo'
subscribe_email: 'Suscríbete para recibir actualizaciones'
subscribe: 'Suscribir'
adsense: 'Anuncio'
followit: 'follow.it'
article:
created_at: 'Publicado hace %s'
updated_at: 'Actualizado hace %s'
more: 'Leer más'
comments: 'Comentarios'
read_time: '%s de lectura'
word_count:
one: 'Aproximadamente %d palabra'
other: 'Aproximadamente %d palabras'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: '¿Te gusta este artículo? Apoya al autor con'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Cómprame un café'
plugin:
backtotop: 'Volver arriba'
visit_count: '%s visitas'
visitor_count: 'Visitado por %s usuarios'
cookie_consent:
message: Este sitio web utiliza cookies para mejorar su experiencia.
dismiss: ¡Entendido!
allow: Permitir cookies
deny: Descenso
link: Aprende más
policy: Política de cookies
search:
search: 'Buscar'
hint: 'Teclea algo...'
no_result: 'No hay resultados para'
untitled: '(Sin título)'
empty_preview: '(Sin vista previa)'
================================================
FILE: languages/fr.yml
================================================
common:
archive:
one: 'Archive'
other: 'Archives'
category:
one: 'Catégorie'
other: 'Catégories'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Article'
other: 'Articles'
page:
one: 'Page'
other: 'Pages'
prev: 'Préc'
next: 'Suiv'
widget:
follow: 'Suivre'
recents: 'Récents'
links: 'Liens'
catalogue: 'Catalogue'
subscribe_email: 'Abonnez-vous aux mises à jour'
subscribe: 'Abonnez-vous'
adsense: 'Publicités'
followit: 'follow.it'
article:
created_at: 'Publié il y a %s'
updated_at: 'Mis à jour il y a %s'
more: 'Lire la suite'
comments: 'Commentaires'
read_time: '%s de lecture'
word_count:
one: 'Environ %d mot'
other: 'Environ %d mots'
licensing:
author: 'Auteur'
created_at: 'Posté le'
updated_at: 'Mis à jour le'
licensed_under: 'Licencié sous'
donate:
title: "Vous aimez cet article? Soutenez l'auteur avec"
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Achetez-moi un café'
plugin:
backtotop: 'Retour en haut'
visit_count: '%s visites'
visitor_count: 'Visité par %s utilisateurs'
cookie_consent:
message: 'Ce site Web utilise des cookies pour améliorer votre expérience.'
dismiss: "C'est bon"
allow: 'Autoriser les cookies'
deny: 'Refuser'
link: 'En savoir plus'
policy: 'Politique relative aux cookies'
search:
search: 'Rechercher'
hint: 'Ecrivez quelque chose...'
no_result: 'Aucun résultat pour'
untitled: '(Sans titre)'
empty_preview: '(Pas de prévisualisation)'
================================================
FILE: languages/id.yml
================================================
common:
archive:
one: 'Arsip'
other: 'Arsip'
category:
one: 'Kategori'
other: 'Kategori'
tag:
one: 'Tag'
other: 'Tag'
post:
one: 'Artikel'
other: 'Artikel'
page:
one: 'Halaman'
other: 'Halaman'
prev: 'Sebelumnya'
next: 'Berikutnya'
widget:
follow: 'IKUTI'
recents: 'Terbaru'
links: 'Tautan'
catalogue: 'Katalog'
subscribe_email: 'Berlangganan untuk pembaruan'
subscribe: 'Berlangganan'
adsense: 'Iklan'
followit: 'follow.it'
article:
created_at: 'Diposting %s'
updated_at: 'Diperbarui %s'
more: 'Selengkapnya'
comments: 'Komentar'
read_time: '%s membaca'
word_count:
one: 'Sekitar %d kata'
other: 'Sekitar %d kata'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Suka dengan artikel ini? Bantu penulis dengan donasi melalui'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Belikan aku kopi'
plugin:
backtotop: 'Kembali ke atas'
visit_count: '%s kunjungan'
visitor_count: 'Dikunjungi oleh %s pengguna'
cookie_consent:
message: Situs web ini menggunakan cookie untuk meningkatkan pengalaman Anda.
dismiss: Mengerti!
allow: Izinkan cookie
deny: Menolak
link: Belajarlah lagi
policy: Kebijakan Cookie
search:
search: 'Pencarian'
hint: 'Tulis Sesuatu..'
no_result: 'Tidak ada hasil untuk'
untitled: '(Tanpa judul)'
empty_preview: '(Tidak ada preview)'
================================================
FILE: languages/it.yml
================================================
common:
archive:
one: 'Archivio'
other: 'Archivi'
category:
one: 'Categoria'
other: 'Categorie'
tag:
one: 'Tag'
other: 'Tag'
post:
one: 'Articolo'
other: 'Articoli'
page:
one: 'Pagina'
other: 'Pagine'
prev: 'Precedente'
next: 'Successivo'
widget:
follow: 'Segui'
recents: 'Recenti'
links: 'Collegamenti'
catalogue: 'Catalogo'
subscribe_email: 'Iscriviti per aggiornamenti'
subscribe: 'Iscriviti'
adsense: 'Pubblicità'
followit: 'follow.it'
article:
created_at: 'Pubblicato il %s'
updated_at: 'Aggiornato il %s'
more: 'Di più'
comments: 'Commenti'
read_time: '%s di lettura'
word_count:
one: 'Circa %d parola'
other: 'Circa %d parole'
licensing:
author: 'Autore'
created_at: 'Pubblicato il'
updated_at: 'Aggiornato il'
licensed_under: 'Licenza'
donate:
title: "Ti è piaciuto questo articolo? Supporta l'autore con"
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Buy me a coffee'
plugin:
backtotop: 'Torna su'
visit_count: '%s visite'
visitor_count: 'Visto da %s usenti'
cookie_consent:
message: Questo sito usa i cookie per migliorare la tua esperienza.
dismiss: "D'accordo!"
allow: Accetta i cookie
deny: Rifiuta
link: Più informazioni
policy: Politica dei cookie
search:
search: 'Cerca'
hint: 'Digita qualcosa...'
no_result: 'Nessun risultato per'
untitled: '(Senza titolo)'
empty_preview: '(Senza anteprima)'
================================================
FILE: languages/ja.yml
================================================
common:
archive:
one: 'アーカイブ'
other: 'アーカイブ'
category:
one: 'カテゴリ'
other: 'カテゴリ'
tag:
one: 'タグ'
other: 'タグ'
post:
one: '投稿'
other: '投稿'
page:
one: 'ページ'
other: 'ページ'
prev: '前'
next: '次'
widget:
follow: 'フォローする'
recents: '最近の記事'
links: 'リンク'
catalogue: 'カタログ'
subscribe_email: '更新を購読する'
subscribe: '購読する'
adsense: '広告'
followit: 'follow.it'
article:
created_at: '%sに投稿'
updated_at: '%sに更新'
more: '続きを読む'
comments: 'コメント'
read_time: '%sで読む'
word_count:
one: '約%d語'
other: '約%d語'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'この記事は気に入りましたか? 著者をサポートする'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'コーヒーを買って'
plugin:
backtotop: 'トップに戻る'
visit_count: '%s回の訪問'
visitor_count: '%s人のユーザーがアクセス'
cookie_consent:
message: このウェブサイトはあなたの経験を改善するためにCookieを使用しています。
dismiss: 了解しました
allow: Cookiesを許可する
deny: 拒否する
link: もっと詳しく知る
policy: Cookieポリシー
search:
search: '検索'
hint: '何かを入力してください...'
no_result: 'の結果はありません'
untitled: '(無題)'
empty_preview: '(プレビューなし)'
================================================
FILE: languages/ko.yml
================================================
common:
archive:
one: '아카이브'
other: '아카이브'
category:
one: '카테고리'
other: '카테고리'
tag:
one: '태그'
other: '태그'
post:
one: '포스트'
other: '포스트'
page:
one: '페이지'
other: '페이지'
prev: '이전'
next: '다음'
widget:
follow: '팔로우'
recents: '최근 글'
links: '링크'
catalogue: '카탈로그'
subscribe_email: '업데이트 소식 받기'
subscribe: '구독'
adsense: '광고'
followit: 'follow.it'
article:
created_at: '%s 게시 됨'
updated_at: '%s 업데이트 됨'
more: '자세히 보기'
comments: '댓글'
read_time: '%s안에 읽기'
word_count:
one: '약 %d 단어'
other: '약 %d 단어'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: '이 글이 마음에 드시나요? 다음을 통해 후원하실 수 있습니다: '
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: '커피 한 잔 사주기'
plugin:
backtotop: '맨 위로'
visit_count: '%s회 방문'
visitor_count: '%s명의 사용자가 방문 함'
cookie_consent:
message: 이 웹 사이트는 귀하의 경험을 향상시키기 위해 Cookie를 사용합니다.
dismiss: 무시
allow: 허용
deny: 거부
link: 더 알아보기
policy: Cookie 정책
search:
search: '검색'
hint: '입력 하세요...'
no_result: '에 대한 결과 없음'
untitled: '(제목 없음)'
empty_preview: '(미리보기 없음)'
================================================
FILE: languages/pl.yml
================================================
common:
archive:
one: 'Archiwum'
other: 'Archiwum'
category:
one: 'Kategoria'
other: 'Kategorie'
tag:
one: 'Tag'
other: 'Tagi'
post:
one: 'Artykuł'
other: 'Artykuły'
page:
one: 'Strona'
other: 'Strony'
prev: 'Poprzedni'
next: 'Następny'
widget:
follow: 'SUBSKRYBUJ'
recents: 'Najnowsze wpisy'
links: 'Linki'
catalogue: 'Spis treści'
subscribe_email: 'Zapisz się, aby otrzymywać aktualizacje'
subscribe: 'Subskrybuj'
adsense: 'Reklama'
followit: 'follow.it'
article:
created_at: 'Opublikowano %s'
updated_at: 'Zaktualizowano %s'
more: 'Czytaj dalej'
comments: 'Komentarze'
read_time: '%s czytania'
word_count:
one: 'Około %d słowa'
other: 'Około %d słów'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Podoba Ci się ten artykuł? Wesprzyj autora za pomocą'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Kup mi kawę'
plugin:
backtotop: 'Powrót do góry'
visit_count: '%s wizyty'
visitor_count: 'Odwiedzone przez %s użytkowników'
cookie_consent:
message: Ta strona korzysta z plików cookie, aby poprawić Twoje doświadczenia.
dismiss: Rozumiem!
allow: Zezwól na pliki cookie
deny: Odrzucać
link: Ucz się więcej
policy: Polityka Cookie
search:
search: 'szukaj'
hint: 'Wpisz coś...'
no_result: 'Brak wyników dla'
untitled: '(Bez tytułu)'
empty_preview: '(Brak podglądu)'
================================================
FILE: languages/pt-BR.yml
================================================
common:
archive:
one: 'Arquivo'
other: 'Arquivos'
category:
one: 'Categoria'
other: 'Categorias'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Artigo'
other: 'Artigos'
page:
one: 'Página'
other: 'Páginas'
prev: 'Anterior'
next: 'Próximo'
widget:
follow: 'Seguir'
recents: 'Recentes'
links: 'Links'
catalogue: 'Catálogo'
subscribe_email: 'Subscrição de atualizações'
subscribe: 'Se inscrever'
adsense: 'Anúncio'
followit: 'follow.it'
article:
created_at: 'Postado %s'
updated_at: 'Atualizado %s'
more: 'Ler Mais'
comments: 'Comentarios'
read_time: '%s lidos'
word_count:
one: 'Cerca de %d palavra'
other: 'Cerca de %d palavras'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Gostou deste artigo? Apoie o autor com'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Me compra um café'
plugin:
backtotop: 'De volta ao topo'
visit_count: '%s visitas'
visitor_count: 'Visitado por %s usuários'
cookie_consent:
message: Este site usa cookies para melhorar sua experiência.
dismiss: Entendi!
allow: Permitir cookies
deny: Declínio
link: Saber mais
policy: Política de Cookies
search:
search: 'Procurar'
hint: 'Digite alguma coisa...'
no_result: 'Sem resultados para'
untitled: '(Sem título)'
empty_preview: '(Não há visualização)'
================================================
FILE: languages/ru.yml
================================================
common:
archive:
one: 'архив'
other: 'архивы'
category:
one: 'категории'
other: 'категории'
tag:
one: 'тег'
other: 'теги'
post:
one: 'пост'
other: 'посты'
page:
one: 'страница'
other: 'страницы'
prev: 'Назад'
next: 'Далее'
widget:
follow: 'Подписаться'
recents: 'недавние'
links: 'ссылки'
catalogue: 'Каталог'
subscribe_email: 'Подпишитесь на обновления'
subscribe: 'Подписывайся'
adsense: 'Рекламное объявление'
followit: 'follow.it'
article:
created_at: 'Опубликовано %s'
updated_at: 'Обновлено %s'
more: 'Читать дальше'
comments: 'Комментарии'
read_time: '%s на чтение'
word_count:
one: 'Около %d слова'
other: 'Примерно %d слова'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Понравилась эта статья? Поддержите автора'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Купи мне кофе'
plugin:
backtotop: 'Вернуться наверх'
visit_count: '%s посещения'
visitor_count: 'Посетили %s пользователя'
cookie_consent:
message: Этот веб-сайт использует файлы cookie для улучшения вашего опыта.
dismiss: Понял!
allow: Разрешить cookies
deny: Отказаться
link: Учить больше
policy: Политика Cookie
search:
search: 'Поиск'
hint: 'Введите что-нибудь...'
no_result: 'Нет результатов по запросу'
untitled: '(Без названия)'
empty_preview: '(Нет предварительного просмотра)'
================================================
FILE: languages/sv.yml
================================================
common:
archive:
one: 'Arkiv'
other: 'Arkiv'
category:
one: 'Kategori'
other: 'Kategorier'
tag:
one: 'Etikett'
other: 'Etiketter'
post:
one: 'Inlägg'
other: 'Inlägg'
page:
one: 'Sida'
other: 'Sidor'
prev: 'Föregående'
next: 'Nästa'
widget:
follow: 'Följ'
recents: 'Senaste'
links: 'Länkar'
catalogue: 'Katalog'
subscribe_email: 'Prenumerera för uppdateringar'
subscribe: 'Prenumerera'
adsense: 'Marknadsföring'
followit: 'follow.it'
article:
created_at: 'Publicerad %s'
updated_at: 'Uppdaterad %s'
more: 'Läs mer'
comments: 'Kommentarer'
read_time: '%s lästid'
word_count:
one: 'Cirka %d ord'
other: 'Cirka %d ord'
licensing:
author: 'Författare'
created_at: 'Publicerad'
updated_at: 'Uppdaterad'
licensed_under: 'Licensierad under'
donate:
title: 'Tycker du om den här artikeln? Stöd författaren genom'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Köp mig en kaffe'
plugin:
backtotop: 'Tillbaka till början'
visit_count: '%s besök'
visitor_count: 'Besökt av %s användare'
cookie_consent:
message: Den här hemsidan använder kakor för att förbättra funktionen.
dismiss: Jag förstår!
allow: Tillåt kakor
deny: Avböj kakor
link: Lär mer
policy: Kakpolicy
search:
search: 'Sök'
hint: 'Skriv någonting...'
no_result: 'Inga sökresultat för'
untitled: '(Utan titel)'
empty_preview: '(Ingen förhandsvisning)'
================================================
FILE: languages/tk.yml
================================================
common:
archive:
one: 'Arhiw'
other: 'Arhiwler'
category:
one: 'Bölüm'
other: 'Bölümler'
tag:
one: 'Teg'
other: 'Tegler'
post:
one: 'Post'
other: 'Postlar'
page:
one: 'Sahypa'
other: 'Sahypalar'
prev: 'Öňki'
next: 'Indiki'
widget:
follow: 'Abuna bol'
recents: 'Täze habarlar'
links: 'Linkler'
catalogue: 'Katalog'
subscribe_email: 'Täzelikler üçin ýazyl'
subscribe: 'Ýazyl'
adsense: 'Mahabat'
followit: 'follow.it'
article:
created_at: 'Paýlaşyldy %s'
updated_at: 'Üýtgedildi %s'
more: 'Dowamy...'
comments: 'Kommentariýa'
read_time: '%s okaldy'
word_count:
one: 'Ortaça %d söz'
other: 'Ortaça %d söz'
licensing:
author: 'Awtor'
created_at: 'Paýlaşdy'
updated_at: 'Üýtgetdi'
licensed_under: 'Resmileşdirilen'
donate:
title: 'Haladynmy? Awtory gollaň'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Buy me a coffee'
plugin:
backtotop: 'Ýokaryk'
visit_count: '%s görüldi'
visitor_count: '%s adam gördi'
cookie_consent:
message: Bu web saýt siziň üçin kuki ulanýar.
dismiss: Düşündim!
allow: Kukini kabul et!
deny: Närazylyk bildir
link: Dowamy...
policy: Kuki syýasaty
search:
search: 'Gözle'
hint: 'Birzatlar ýazyň...'
no_result: 'Tapylmady'
untitled: 'Atlandyrylmadyk'
empty_preview: 'Boş'
================================================
FILE: languages/tr.yml
================================================
common:
archive:
one: 'Arşiv'
other: 'Arşivler'
category:
one: 'Kategori'
other: 'Kategoriler'
tag:
one: 'Etiket'
other: 'Etiketler'
post:
one: 'Gönderi'
other: 'Gönderiler'
page:
one: 'Sayfa'
other: 'Sayfalar'
prev: 'Önceki'
next: 'Sonraki'
widget:
follow: 'TAKİP ET'
recents: 'Son'
links: 'Linkler'
catalogue: 'Katalog'
subscribe_email: 'Güncellemeler için abone olun'
subscribe: 'Abone ol'
adsense: 'İlan'
followit: 'follow.it'
article:
created_at: '%s yayınlandı'
updated_at: '%s güncellendi'
more: 'Daha fazla oku'
comments: 'Yorumlar'
read_time: '%s okuma süresi'
word_count:
one: 'Yaklaşık %d kelime'
other: 'Yaklaşık %d kelime'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Bu makaleyi beğendiniz mi? Yazarı şununla destekleyin'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Bana bir kahve al'
plugin:
backtotop: 'Başa dönüş'
visit_count: '%s ziyaret'
visitor_count: '%s kullanıcı tarafından ziyaret edildi'
cookie_consent:
message: Bu web sitesi, deneyiminizi geliştirmek için çerezler kullanır.
dismiss: Anladım!
allow: Çerezlere izin ver
deny: Reddet
link: Daha fazla bilgi edin
policy: Çerez politikası
search:
search: 'Ara'
hint: 'Bir şeyler yaz...'
no_result: 'İçin sonuç yok'
untitled: '(Başlıksız)'
empty_preview: '(Önizleme yok)'
================================================
FILE: languages/vn.yml
================================================
common:
archive:
one: 'Lưu trữ'
other: 'Lưu trữ'
category:
one: 'Thể loại'
other: 'Thể loại'
tag:
one: 'Nhãn'
other: 'Nhãn'
post:
one: 'Bài viết'
other: 'Bài viết'
page:
one: 'Trang'
other: 'Trang'
prev: 'Trước'
next: 'Sau'
widget:
follow: 'Theo dõi'
recents: 'Gần đây'
links: 'Link'
catalogue: 'Mục lục'
subscribe_email: 'Theo dõi các bản cập nhật'
subscribe: 'Theo dõi'
adsense: 'Quảng cáo'
followit: 'follow.it'
article:
created_at: 'Đã đăng %s'
updated_at: 'Đã cập nhật %s'
more: 'Đọc thêm'
comments: 'Bình luận'
read_time: '%s đọc'
word_count:
one: 'Khoảng %d từ'
other: 'Khoảng %d từ'
licensing:
author: 'Author'
created_at: 'Posted on'
updated_at: 'Updated on'
licensed_under: 'Licensed under'
donate:
title: 'Bạn đọc có thể ủng hộ blog qua'
afdian: 'Afdian.net'
alipay: 'Alipay'
wechat: 'Wechat'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: 'Mua cho tôi một ly cà phê'
plugin:
backtotop: 'Trở lai đầu trang'
visit_count: '%s Bạn đọc'
visitor_count: 'Thăm bởi %s bạn đọc'
cookie_consent:
message: Trang web này sử dụng cookie để cải thiện trải nghiệm của bạn.
dismiss: Hiểu rồi!
allow: Cho phép cookie
deny: Từ chối
link: Tìm hiểu thêm
policy: Chính sách Cookie
search:
search: 'Tìm kiếm'
hint: 'Gõ gì đó...'
no_result: 'Không có kết quả cho'
untitled: '(Không có tiêu đề)'
empty_preview: '(Không có xem trước)'
================================================
FILE: languages/zh-CN.yml
================================================
common:
archive:
one: '归档'
other: '归档'
category:
one: '分类'
other: '分类'
tag:
one: '标签'
other: '标签'
post:
one: '文章'
other: '文章'
page:
one: '页面'
other: '页面'
prev: '上一页'
next: '下一页'
widget:
follow: '关注我'
recents: '最新文章'
links: '链接'
catalogue: '目录'
subscribe_email: '订阅更新'
subscribe: '订阅'
adsense: '广告'
followit: 'follow.it'
article:
created_at: '%s发表'
updated_at: '%s更新'
more: '阅读更多'
comments: '评论'
read_time: '%s读完'
word_count:
one: '大约%d个字'
other: '大约%d个字'
licensing:
author: '作者'
created_at: '发布于'
updated_at: '更新于'
licensed_under: '许可协议'
donate:
title: '喜欢这篇文章?打赏一下作者吧'
afdian: '爱发电'
alipay: '支付宝'
wechat: '微信'
paypal: 'Paypal'
patreon: 'Patreon'
buymeacoffee: '送我杯咖啡'
plugin:
backtotop: '回到顶端'
visit_count: '%s次访问'
visitor_count: '共%s个访客'
cookie_consent:
message: 此网站使用Cookie来改善您的体验。
dismiss: 知道了!
allow: 允许使用Cookie
deny: 拒绝
link: 了解更多
policy: Cookie政策
search:
search: '搜索'
hint: '想要查找什么...'
no_result: '未找到搜索结果'
untitled: '(无标题)'
empty_preview: '(无内容预览)'
================================================
FILE: languages/zh-TW.yml
================================================
common:
archive:
one: '彙整'
other: '彙整'
category:
one: '分類'
other: '分類'
tag:
one: '標籤'
other: '標籤'
post:
one: '文章'
other: '文章'
page:
one: '頁面'
other: '頁面'
prev: '上一頁'
next: '下一頁'
widget:
follow: '追蹤'
recents: '最新文章'
links: '連結'
catalogue: '文章目錄'
subscribe_email: '訂閱 Email'
subscribe: '訂閱'
adsense: '廣告'
followit: 'follow.it'
article:
created_at: '%s發表'
updated_at: '%s更新'
more: '繼續閱讀'
comments: '評論'
read_time: '%s讀完'
word_count:
one: '大約%d個字'
other: '大約%d個字'
licensing:
author: '作者'
created_at: '發表於'
updated_at: '更新於'
licensed_under: '許可協議'
donate:
title: '喜歡這篇文章嗎? 贊助一下作者吧!'
afdian: '愛發電'
alipay: '支付寶'
wechat: 'WeChat'
paypal: 'PayPal'
patreon: 'Patreon'
buymeacoffee: '送我杯咖啡'
plugin:
backtotop: '回到頁首'
visit_count: '%s次訪問'
visitor_count: '共%s個訪客'
cookie_consent:
message: 此網站使用Cookie來改善您的體驗。
dismiss: 知道了!
allow: 允許使用Cookie
deny: 拒絕
link: 了解更多
policy: Cookie政策
search:
search: '搜尋'
hint: '請輸入關鍵字...'
no_result: '未找到搜索結果'
untitled: '(無標題)'
empty_preview: '(無內容預覽)'
================================================
FILE: layout/archive.jsx
================================================
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
const ArticleMedia = require('hexo-component-inferno/lib/view/common/article_media');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { url_for, __, date_xml, date } = helper;
const language = toMomentLocale(page.lang || page.language || config.language);
function renderArticleList(posts, year, month = null) {
const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));
return <div class="card">
<div class="card-content">
<h3 class="tag is-primary">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
<div class="timeline">
{posts.map(post => {
const categories = post.categories.map(category => ({
url: url_for(category.path),
name: category.name
}));
return <ArticleMedia
url={url_for(post.link || post.path)}
title={post.title}
date={date(post.date)}
dateXml={date_xml(post.date)}
categories={categories}
thumbnail={post.thumbnail ? url_for(post.thumbnail) : null} />;
})}
</div>
</div>
</div>;
}
let articleList;
if (!page.year) {
const years = {};
page.posts.each(p => { years[p.date.year()] = null; });
articleList = Object.keys(years).sort((a, b) => b - a).map(year => {
const posts = page.posts.filter(p => p.date.year() === parseInt(year, 10));
return renderArticleList(posts, year, null);
});
} else {
articleList = renderArticleList(page.posts, page.year, page.month);
}
return <Fragment>
{articleList}
{page.total > 1 ? <Paginator
current={page.current}
total={page.total}
baseUrl={page.base}
path={config.pagination_dir}
urlFor={url_for}
prevTitle={__('common.prev')}
nextTitle={__('common.next')} /> : null}
</Fragment>;
}
};
================================================
FILE: layout/categories.jsx
================================================
const { Component } = require('inferno');
const Categories = require('hexo-component-inferno/lib/view/widget/categories');
module.exports = class extends Component {
render() {
const { site, page, helper } = this.props;
return <Categories.Cacheable site={site} page={page} helper={helper} />;
}
};
================================================
FILE: layout/category.jsx
================================================
const { Component, Fragment } = require('inferno');
const Index = require('./index');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { url_for, _p } = helper;
return <Fragment>
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href={url_for('/categories/')}>{_p('common.category', Infinity)}</a></li>
{page.parents.map(category => {
return <li><a href={url_for(category.path)}>{category.name}</a></li>;
})}
<li class="is-active"><a href="#" aria-current="page">{page.category}</a></li>
</ul>
</nav>
</div>
</div>
<Index config={config} page={page} helper={helper} />
</Fragment>;
}
};
================================================
FILE: layout/comment/.gitkeep
================================================
================================================
FILE: layout/common/article.jsx
================================================
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Share = require('./share');
const Donates = require('./donates');
const Comment = require('./comment');
const ArticleLicensing = require('hexo-component-inferno/lib/view/misc/article_licensing');
/**
* Get the word count of text.
*/
function getWordCount(content) {
if (typeof content === 'undefined') {
return 0;
}
content = content.replace(/<\/?[a-z][^>]*>/gi, '');
content = content.trim();
return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
}
module.exports = class extends Component {
render() {
const { config, helper, page, index } = this.props;
const { article, plugins } = config;
const { url_for, date, date_xml, __, _p } = helper;
const defaultLanguage = Array.isArray(config.language) && config.language.length ? config.language[0] : config.language;
const indexLanguage = toMomentLocale(defaultLanguage || 'en');
const language = toMomentLocale(page.lang || page.language || defaultLanguage || 'en');
const cover = page.cover ? url_for(page.cover) : null;
const updateTime = article && article.update_time !== undefined ? article.update_time : true;
const isUpdated = page.updated && !moment(page.date).isSame(moment(page.updated));
const shouldShowUpdated = page.updated && ((updateTime === 'auto' && isUpdated) || updateTime === true);
return <Fragment>
{/* Main content */}
<div class="card">
{/* Thumbnail */}
{cover ? <div class="card-image">
{index ? <a href={url_for(page.link || page.path)} class="image is-7by3">
<img class="fill" src={cover} alt={page.title || cover} />
</a> : <span class="image is-7by3">
<img class="fill" src={cover} alt={page.title || cover} />
</span>}
</div> : null}
<article class={`card-content article${'direction' in page ? ' ' + page.direction : ''}`} role="article">
{/* Metadata */}
{page.layout !== 'page' ? <div class="article-meta is-size-7 is-uppercase level is-mobile">
<div class="level-left">
{/* PIN Icon */}
{page.top ? <i class="fas fa-thumbtack level-item" title="Pinned"></i> : null}
{/* Creation Date */}
{page.date && <span class="level-item" dangerouslySetInnerHTML={{
__html: _p('article.created_at', `<time dateTime="${date_xml(page.date)}" title="${new Date(page.date).toLocaleString()}">${date(page.date)}</time>`)
}}></span>}
{/* Last Update Date */}
{shouldShowUpdated && <span class="level-item" dangerouslySetInnerHTML={{
__html: _p('article.updated_at', `<time dateTime="${date_xml(page.updated)}" title="${new Date(page.updated).toLocaleString()}">${date(page.updated)}</time>`)
}}></span>}
{/* author */}
{page.author ? <span class="level-item"> {page.author} </span> : null}
{/* Categories */}
{page.categories && page.categories.length ? <span class="level-item">
{(() => {
const categories = [];
page.categories.forEach((category, i) => {
categories.push(<a class="link-muted" href={url_for(category.path)}>{category.name}</a>);
if (i < page.categories.length - 1) {
categories.push(<span> / </span>);
}
});
return categories;
})()}
</span> : null}
{/* Read time */}
{article && article.readtime && article.readtime === true ? <span class="level-item">
{(() => {
const words = getWordCount(page._content);
const time = moment.duration((words / 150.0) * 60, 'seconds');
return `${_p('article.read_time', time.locale(index ? indexLanguage : language).humanize())} (${_p('article.word_count', words)})`;
})()}
</span> : null}
{/* Visitor counter */}
{!index && plugins && plugins.busuanzi === true ? <span class="level-item" id="busuanzi_container_page_pv" dangerouslySetInnerHTML={{
__html: _p('plugin.visit_count', '<span id="busuanzi_value_page_pv">0</span>')
}}></span> : null}
</div>
</div> : null}
{/* Title */}
{page.title !== '' && index ? <p class="title is-3 is-size-4-mobile"><a class="link-muted" href={url_for(page.link || page.path)}>{page.title}</a></p> : null}
{page.title !== '' && !index ? <h1 class="title is-3 is-size-4-mobile">{page.title}</h1> : null}
{/* Content/Excerpt */}
<div class="content" dangerouslySetInnerHTML={{ __html: index && page.excerpt ? page.excerpt : page.content }}></div>
{/* Licensing block */}
{!index && article && article.licenses && Object.keys(article.licenses)
? <ArticleLicensing.Cacheable page={page} config={config} helper={helper} /> : null}
{/* Tags */}
{!index && page.tags && page.tags.length ? <div class="article-tags is-size-7 mb-4">
<span class="mr-2">#</span>
{page.tags.map(tag => {
return <a class="link-muted mr-2" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
})}
</div> : null}
{/* "Read more" button */}
{index && page.excerpt ? <a class="article-more button is-small is-size-7" href={`${url_for(page.link || page.path)}#more`}>{__('article.more')}</a> : null}
{/* Share button */}
{!index ? <Share config={config} page={page} helper={helper} /> : null}
</article>
</div>
{/* Donate button */}
{!index ? <Donates config={config} helper={helper} /> : null}
{/* Post navigation */}
{!index && (page.prev || page.next) ? <nav class="post-navigation mt-4 level is-mobile">
{page.prev ? <div class="level-start">
<a class={`article-nav-prev level level-item${!page.prev ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.prev.path)}>
<i class="level-item fas fa-chevron-left"></i>
<span class="level-item">{page.prev.title}</span>
</a>
</div> : null}
{page.next ? <div class="level-end">
<a class={`article-nav-next level level-item${!page.next ? ' is-hidden-mobile' : ''} link-muted`} href={url_for(page.next.path)}>
<span class="level-item">{page.next.title}</span>
<i class="level-item fas fa-chevron-right"></i>
</a>
</div> : null}
</nav> : null}
{/* Comment */}
{!index ? <Comment config={config} page={page} helper={helper} /> : null}
</Fragment>;
}
};
================================================
FILE: layout/common/comment.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const logger = createLogger.default();
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { __ } = helper;
const { comment } = config;
if (!comment || typeof comment.type !== 'string') {
return null;
}
return <div class="card" id="comments">
<div class="card-content">
<h3 class="title is-5">{__('article.comments')}</h3>
{(() => {
try {
let Comment = view.require('comment/' + comment.type);
Comment = Comment.Cacheable ? Comment.Cacheable : Comment;
return <Comment config={config} page={page} helper={helper} comment={comment} />;
} catch (e) {
logger.w(`Icarus cannot load comment "${comment.type}"`);
return null;
}
})()}
</div>
</div>;
}
};
================================================
FILE: layout/common/donates.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const logger = createLogger.default();
module.exports = class extends Component {
render() {
const { config, helper } = this.props;
const { __ } = helper;
const { donates = [] } = config;
if (!Array.isArray(donates) || !donates.length) {
return null;
}
return <div class="card">
<div class="card-content">
<h3 class="menu-label has-text-centered">{__('donate.title')}</h3>
<div class="buttons is-centered">
{donates.map(service => {
const type = service.type;
if (typeof type === 'string') {
try {
let Donate = view.require('donate/' + type);
Donate = Donate.Cacheable ? Donate.Cacheable : Donate;
return <Donate helper={helper} donate={service} />;
} catch (e) {
logger.w(`Icarus cannot load donate button "${type}"`);
}
}
return null;
})}
</div>
</div>
</div>;
}
};
================================================
FILE: layout/common/footer.jsx
================================================
const { Component } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class Footer extends Component {
render() {
const {
logo,
logoUrl,
siteUrl,
siteTitle,
siteYear,
author,
links,
copyright,
showVisitorCounter,
visitorCounterTitle
} = this.props;
let footerLogo = '';
if (logo) {
if (logo.text) {
footerLogo = logo.text;
} else {
footerLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
}
} else {
footerLogo = siteTitle;
}
return <footer class="footer">
<div class="container">
<div class="level">
<div class="level-start">
<a class="footer-logo is-block mb-2" href={siteUrl}>
{footerLogo}
</a>
<p class="is-size-7">
<span dangerouslySetInnerHTML={{ __html: `© ${siteYear} ${author || siteTitle}` }}></span>
Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a> &
<a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
{showVisitorCounter ? <br /> : null}
{showVisitorCounter ? <span id="busuanzi_container_site_uv"
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
</p>
{copyright ? <p class="is-size-7" dangerouslySetInnerHTML={{ __html: copyright }}></p> : null}
</div>
<div class="level-end">
{Object.keys(links).length ? <div class="field has-addons">
{Object.keys(links).map(name => {
const link = links[name];
return <p class="control">
<a class={`button is-transparent ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? <i class={link.icon}></i> : name}
</a>
</p>;
})}
</div> : null}
</div>
</div>
</div>
</footer>;
}
}
module.exports = cacheComponent(Footer, 'common.footer', props => {
const { config, helper } = props;
const { url_for, _p, date } = helper;
const { logo, title, author, footer, plugins } = config;
const links = {};
if (footer && footer.links) {
Object.keys(footer.links).forEach(name => {
const link = footer.links[name];
links[name] = {
url: url_for(typeof link === 'string' ? link : link.url),
icon: link.icon
};
});
}
return {
logo,
logoUrl: url_for(logo),
siteUrl: url_for('/'),
siteTitle: title,
siteYear: date(new Date(), 'YYYY'),
author,
links,
copyright: footer?.copyright ?? '',
showVisitorCounter: plugins && plugins.busuanzi === true,
visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>')
};
});
================================================
FILE: layout/common/head.jsx
================================================
const { Component } = require('inferno');
const MetaTags = require('hexo-component-inferno/lib/view/misc/meta');
const WebApp = require('hexo-component-inferno/lib/view/misc/web_app');
const OpenGraph = require('hexo-component-inferno/lib/view/misc/open_graph');
const StructuredData = require('hexo-component-inferno/lib/view/misc/structured_data');
const Plugins = require('./plugins');
function getPageTitle(page, siteTitle, helper) {
let title = page.title;
if (helper.is_archive()) {
title = helper._p('common.archive', Infinity);
if (helper.is_month()) {
title += ': ' + page.year + '/' + page.month;
} else if (helper.is_year()) {
title += ': ' + page.year;
}
} else if (helper.is_category()) {
title = helper._p('common.category', 1) + ': ' + page.category;
} else if (helper.is_tag()) {
title = helper._p('common.tag', 1) + ': ' + page.tag;
} else if (helper.is_categories()) {
title = helper._p('common.category', Infinity);
} else if (helper.is_tags()) {
title = helper._p('common.tag', Infinity);
}
return [title, siteTitle].filter(str => typeof str !== 'undefined' && str.trim() !== '').join(' - ');
}
module.exports = class extends Component {
render() {
const { site, config, helper, page } = this.props;
const { url_for, cdn, fontcdn, iconcdn, is_post } = helper;
const {
url,
head = {},
article,
highlight,
variant = 'default'
} = config;
const {
meta = [],
manifest = {},
open_graph = {},
structured_data = {},
canonical_url = page.permalink,
rss,
favicon
} = head;
const noIndex = helper.is_archive() || helper.is_category() || helper.is_tag();
const language = page.lang || page.language || config.language;
const fontCssUrl = {
default: fontcdn('Ubuntu:wght@400;600&family=Source+Code+Pro', 'css2'),
cyberpunk: fontcdn('Oxanium:wght@300;400;600&family=Roboto+Mono', 'css2')
};
let hlTheme, images;
if (highlight && highlight.enable === false) {
hlTheme = null;
} else if (article && article.highlight && article.highlight.theme) {
hlTheme = article.highlight.theme;
} else {
hlTheme = 'atom-one-light';
}
if (typeof page.og_image === 'string') {
images = [page.og_image];
} else if (typeof page.cover === 'string') {
images = [url_for(page.cover)];
} else if (typeof page.thumbnail === 'string') {
images = [url_for(page.thumbnail)];
} else if (article && typeof article.og_image === 'string') {
images = [article.og_image];
} else if (page.content && page.content.includes('<img')) {
let img;
images = [];
const imgPattern = /<img [^>]*src=['"]([^'"]+)([^>]*>)/gi;
while ((img = imgPattern.exec(page.content)) !== null) {
images.push(img[1]);
}
} else {
images = [url_for('/img/og_image.png')];
}
let adsenseClientId = null;
if (Array.isArray(config.widgets)) {
const widget = config.widgets.find(widget => widget.type === 'adsense');
if (widget) {
adsenseClientId = widget.client_id;
}
}
let openGraphImages = images;
if ((typeof open_graph === 'object' && open_graph !== null)
&& ((Array.isArray(open_graph.image) && open_graph.image.length > 0) || typeof open_graph.image === 'string')) {
openGraphImages = open_graph.image;
} else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
openGraphImages = page.photos;
}
let structuredImages = images;
if ((typeof structured_data === 'object' && structured_data !== null)
&& ((Array.isArray(structured_data.image) && structured_data.image.length > 0) || typeof structured_data.image === 'string')) {
structuredImages = structured_data.image;
} else if ((Array.isArray(page.photos) && page.photos.length > 0) || typeof page.photos === 'string') {
structuredImages = page.photos;
}
let followItVerificationCode = null;
if (Array.isArray(config.widgets)) {
const widget = config.widgets.find(widget => widget.type === 'followit');
if (widget) {
followItVerificationCode = widget.verification_code;
}
}
return <head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
{noIndex ? <meta name="robots" content="noindex" /> : null}
{meta && meta.length ? <MetaTags meta={meta} /> : null}
<title>{getPageTitle(page, config.title, helper)}</title>
<WebApp.Cacheable
helper={helper}
favicon={favicon}
icons={manifest.icons}
themeColor={manifest.theme_color}
name={manifest.name || config.title} />
{typeof open_graph === 'object' && open_graph !== null ? <OpenGraph
type={open_graph.type || (is_post(page) ? 'article' : 'website')}
title={open_graph.title || page.title || config.title}
date={page.date}
updated={page.updated}
author={open_graph.author || config.author}
description={open_graph.description || page.description || page.excerpt || page.content || config.description}
keywords={(page.tags && page.tags.length ? page.tags : undefined) || config.keywords}
url={open_graph.url || page.permalink || url}
images={openGraphImages}
siteName={open_graph.site_name || config.title}
language={language}
twitterId={open_graph.twitter_id}
twitterCard={open_graph.twitter_card}
twitterSite={open_graph.twitter_site}
googlePlus={open_graph.google_plus}
facebookAdmins={open_graph.fb_admins}
facebookAppId={open_graph.fb_app_id} /> : null}
{typeof structured_data === 'object' && structured_data !== null ? <StructuredData
title={structured_data.title || page.title || config.title}
description={structured_data.description || page.description || page.excerpt || page.content || config.description}
url={structured_data.url || page.permalink || url}
author={structured_data.author || config.author}
publisher={structured_data.publisher || config.title}
publisherLogo={structured_data.publisher_logo || config.logo}
date={page.date}
updated={page.updated}
images={structuredImages} /> : null}
{canonical_url ? <link rel="canonical" href={canonical_url} /> : null}
{rss ? <link rel="alternate" href={url_for(rss)} title={config.title} type="application/atom+xml" /> : null}
{favicon ? <link rel="icon" href={url_for(favicon)} /> : null}
<link rel="stylesheet" href={iconcdn()} />
{hlTheme ? <link data-pjax rel="stylesheet" href={cdn('highlight.js', '11.7.0', 'styles/' + hlTheme + '.css')} /> : null}
<link rel="stylesheet" href={fontCssUrl[variant]} />
<link data-pjax rel="stylesheet" href={url_for('/css/' + variant + '.css')} />
<Plugins site={site} config={config} helper={helper} page={page} head={true} />
{adsenseClientId ? <script data-ad-client={adsenseClientId}
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" async></script> : null}
{followItVerificationCode ? <meta name="follow.it-verification-code" content={followItVerificationCode} /> : null}
</head>;
}
};
================================================
FILE: layout/common/navbar.jsx
================================================
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
const classname = require('hexo-component-inferno/lib/util/classname');
function isSameLink(a, b) {
function santize(url) {
let paths = url.replace(/(^\w+:|^)\/\//, '').split('#')[0].split('/').filter(p => p.trim() !== '');
if (paths.length > 0 && paths[paths.length - 1].trim() === 'index.html') {
paths = paths.slice(0, paths.length - 1);
}
return paths.join('/');
}
return santize(a) === santize(b);
}
class Navbar extends Component {
render() {
const {
logo,
logoUrl,
siteUrl,
siteTitle,
menu,
links,
showToc,
tocTitle,
showSearch,
searchTitle
} = this.props;
let navbarLogo = '';
if (logo) {
if (logo.text) {
navbarLogo = logo.text;
} else {
navbarLogo = <img src={logoUrl} alt={siteTitle} height="28" />;
}
} else {
navbarLogo = siteTitle;
}
return <nav class="navbar navbar-main">
<div class="container navbar-container">
<div class="navbar-brand justify-content-center">
<a class="navbar-item navbar-logo" href={siteUrl}>
{navbarLogo}
</a>
</div>
<div class="navbar-menu">
{Object.keys(menu).length ? <div class="navbar-start">
{Object.keys(menu).map(name => {
const item = menu[name];
return <a class={classname({ 'navbar-item': true, 'is-active': item.active })} href={item.url}>{name}</a>;
})}
</div> : null}
<div class="navbar-end">
{Object.keys(links).length ? <Fragment>
{Object.keys(links).map(name => {
const link = links[name];
return <a class="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? <i class={link.icon}></i> : name}
</a>;
})}
</Fragment> : null}
{showToc ? <a class="navbar-item is-hidden-tablet catalogue" title={tocTitle} href="javascript:;">
<i class="fas fa-list-ul"></i>
</a> : null}
{showSearch ? <a class="navbar-item search" title={searchTitle} href="javascript:;">
<i class="fas fa-search"></i>
</a> : null}
</div>
</div>
</div>
</nav>;
}
}
module.exports = cacheComponent(Navbar, 'common.navbar', props => {
const { config, helper, page } = props;
const { url_for, _p, __ } = helper;
const { logo, title, navbar, widgets, search } = config;
const hasTocWidget = Array.isArray(widgets) && widgets.find(widget => widget.type === 'toc');
const showToc = (config.toc === true || page.toc) && hasTocWidget && ['page', 'post'].includes(page.layout);
const menu = {};
if (navbar && navbar.menu) {
const pageUrl = typeof page.path !== 'undefined' ? url_for(page.path) : '';
Object.keys(navbar.menu).forEach(name => {
const url = url_for(navbar.menu[name]);
const active = isSameLink(url, pageUrl);
menu[name] = { url, active };
});
}
const links = {};
if (navbar && navbar.links) {
Object.keys(navbar.links).forEach(name => {
const link = navbar.links[name];
links[name] = {
url: url_for(typeof link === 'string' ? link : link.url),
icon: link.icon
};
});
}
return {
logo,
logoUrl: url_for(logo),
siteUrl: url_for('/'),
siteTitle: title,
menu,
links,
showToc,
tocTitle: _p('widget.catalogue', Infinity),
showSearch: search && search.type,
searchTitle: __('search.search')
};
});
================================================
FILE: layout/common/plugins.jsx
================================================
const createLogger = require('hexo-log');
const { Component, Fragment } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const logger = createLogger.default();
module.exports = class extends Component {
render() {
const { site, config, page, helper, head } = this.props;
const { plugins = [] } = config;
return <Fragment>
{Object.keys(plugins).map(name => {
// plugin is not enabled
if (!plugins[name]) {
return null;
}
try {
let Plugin = view.require('plugin/' + name);
Plugin = Plugin.Cacheable ? Plugin.Cacheable : Plugin;
return <Plugin site={site} config={config} page={page} helper={helper} plugin={plugins[name]} head={head} />;
} catch (e) {
logger.w(`Icarus cannot load plugin "${name}"`);
return null;
}
})}
</Fragment>;
}
};
================================================
FILE: layout/common/scripts.jsx
================================================
const { Component, Fragment } = require('inferno');
const { toMomentLocale } = require('hexo/dist/plugins/helper/date');
const Plugins = require('./plugins');
module.exports = class extends Component {
render() {
const { site, config, helper, page } = this.props;
const { url_for, cdn } = helper;
const { article } = config;
const language = toMomentLocale(page.lang || page.language || config.language || 'en');
let fold = 'unfolded';
let clipboard = true;
if (article && article.highlight) {
if (typeof article.highlight.clipboard !== 'undefined') {
clipboard = !!article.highlight.clipboard;
}
if (typeof article.highlight.fold === 'string') {
fold = article.highlight.fold;
}
}
const embeddedConfig = `var IcarusThemeSettings = {
article: {
highlight: {
clipboard: ${clipboard},
fold: '${fold}'
}
}
};`;
return <Fragment>
<script src={cdn('jquery', '3.3.1', 'dist/jquery.min.js')}></script>
<script src={cdn('moment', '2.22.2', 'min/moment-with-locales.min.js')}></script>
{clipboard && <script src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')} defer></script>}
<script dangerouslySetInnerHTML={{ __html: `moment.locale("${language}");` }}></script>
<script dangerouslySetInnerHTML={{ __html: embeddedConfig }}></script>
<script data-pjax src={url_for('/js/column.js')}></script>
<Plugins site={site} config={config} page={page} helper={helper} head={false} />
<script data-pjax src={url_for('/js/main.js')} defer></script>
</Fragment>;
}
};
================================================
FILE: layout/common/search.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const logger = createLogger.default();
module.exports = class extends Component {
render() {
const { config, helper } = this.props;
const { search } = config;
if (!search || typeof search.type !== 'string') {
return null;
}
try {
let Search = view.require('search/' + search.type);
Search = Search.Cacheable ? Search.Cacheable : Search;
return <Search config={config} helper={helper} search={search} />;
} catch (e) {
logger.w(`Icarus cannot load search "${search.type}"`);
return null;
}
}
};
================================================
FILE: layout/common/share.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const logger = createLogger.default();
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { share } = config;
if (!share || typeof share.type !== 'string') {
return null;
}
try {
let Share = view.require('share/' + share.type);
Share = Share.Cacheable ? Share.Cacheable : Share;
return <Share config={config} page={page} helper={helper} share={share} />;
} catch (e) {
logger.w(`Icarus cannot load share button "${share.type}"`);
return null;
}
}
};
================================================
FILE: layout/common/widgets.jsx
================================================
const createLogger = require('hexo-log');
const { Component } = require('inferno');
const view = require('hexo-component-inferno/lib/core/view');
const classname = require('hexo-component-inferno/lib/util/classname');
const logger = createLogger.default();
function formatWidgets(widgets) {
const result = {};
if (Array.isArray(widgets)) {
widgets.filter(widget => typeof widget === 'object').forEach(widget => {
if ('position' in widget && (widget.position === 'left' || widget.position === 'right')) {
if (!(widget.position in result)) {
result[widget.position] = [widget];
} else {
result[widget.position].push(widget);
}
}
});
}
return result;
}
function hasColumn(widgets, position, config, page) {
const showToc = (config.toc === true) && ['page', 'post'].includes(page.layout);
if (Array.isArray(widgets)) {
return typeof widgets.find(widget => {
if (widget.type === 'toc' && !showToc) {
return false;
}
return widget.position === position;
}) !== 'undefined';
}
return false;
}
function getColumnCount(widgets, config, page) {
return [hasColumn(widgets, 'left', config, page), hasColumn(widgets, 'right', config, page)].filter(v => !!v).length + 1;
}
function getColumnSizeClass(columnCount) {
switch (columnCount) {
case 2:
return 'is-4-tablet is-4-desktop is-4-widescreen';
case 3:
return 'is-4-tablet is-4-desktop is-3-widescreen';
}
return '';
}
function getColumnVisibilityClass(columnCount, position) {
if (columnCount === 3 && position === 'right') {
return 'is-hidden-touch is-hidden-desktop-only';
}
return '';
}
function getColumnOrderClass(position) {
return position === 'left' ? 'order-1' : 'order-3';
}
function isColumnSticky(config, position) {
return typeof config.sidebar === 'object'
&& position in config.sidebar
&& config.sidebar[position].sticky === true;
}
class Widgets extends Component {
render() {
const { site, config, helper, page, position } = this.props;
const widgets = formatWidgets(config.widgets)[position] || [];
const columnCount = getColumnCount(config.widgets, config, page);
if (!widgets.length) {
return null;
}
return <div class={classname({
'column': true,
['column-' + position]: true,
[getColumnSizeClass(columnCount)]: true,
[getColumnVisibilityClass(columnCount, position)]: true,
[getColumnOrderClass(position)]: true,
'is-sticky': isColumnSticky(config, position)
})}>
{widgets.map(widget => {
// widget type is not defined
if (!widget.type) {
return null;
}
try {
let Widget = view.require('widget/' + widget.type);
Widget = Widget.Cacheable ? Widget.Cacheable : Widget;
return <Widget site={site} helper={helper} config={config} page={page} widget={widget} />;
} catch (e) {
logger.w(`Icarus cannot load widget "${widget.type}"`);
}
return null;
})}
{position === 'left' && hasColumn(config.widgets, 'right', config, page) ? <div class={classname({
'column-right-shadow': true,
'is-hidden-widescreen': true,
'is-sticky': isColumnSticky(config, 'right')
})}></div> : null}
</div>;
}
}
Widgets.getColumnCount = getColumnCount;
module.exports = Widgets;
================================================
FILE: layout/donate/.gitkeep
================================================
================================================
FILE: layout/index.jsx
================================================
const { Component, Fragment } = require('inferno');
const Paginator = require('hexo-component-inferno/lib/view/misc/paginator');
const Article = require('./common/article');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { __, url_for } = helper;
return <Fragment>
{page.posts.map(post => <Article config={config} page={post} helper={helper} index={true} />)}
{page.total > 1 ? <Paginator
current={page.current}
total={page.total}
baseUrl={page.base}
path={config.pagination_dir}
urlFor={url_for}
prevTitle={__('common.prev')}
nextTitle={__('common.next')} /> : null}
</Fragment>;
}
};
================================================
FILE: layout/layout.jsx
================================================
const { Component } = require('inferno');
const classname = require('hexo-component-inferno/lib/util/classname');
const Head = require('./common/head');
const Navbar = require('./common/navbar');
const Widgets = require('./common/widgets');
const Footer = require('./common/footer');
const Scripts = require('./common/scripts');
const Search = require('./common/search');
module.exports = class extends Component {
render() {
const { site, config, page, helper, body } = this.props;
const language = page.lang || page.language || config.language;
const columnCount = Widgets.getColumnCount(config.widgets, config, page);
return <html lang={language ? language.substr(0, 2) : ''}>
<Head site={site} config={config} helper={helper} page={page} />
<body class={`is-${columnCount}-column`}>
<Navbar config={config} helper={helper} page={page} />
<section class="section">
<div class="container">
<div class="columns">
<div class={classname({
column: true,
'order-2': true,
'column-main': true,
'is-12': columnCount === 1,
'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3
})} dangerouslySetInnerHTML={{ __html: body }}></div>
<Widgets site={site} config={config} helper={helper} page={page} position={'left'} />
<Widgets site={site} config={config} helper={helper} page={page} position={'right'} />
</div>
</div>
</section>
<Footer config={config} helper={helper} />
<Scripts site={site} config={config} helper={helper} page={page} />
<Search config={config} helper={helper} />
</body>
</html>;
}
};
================================================
FILE: layout/misc/.gitkeep
================================================
================================================
FILE: layout/page.jsx
================================================
const { Component } = require('inferno');
const Article = require('./common/article');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
return <Article config={config} page={page} helper={helper} index={false} />;
}
};
================================================
FILE: layout/plugin/animejs.jsx
================================================
const { Component } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class AnimeJs extends Component {
render() {
if (this.props.head) {
return <style dangerouslySetInnerHTML={{ __html: 'body>.footer,body>.navbar,body>.section{opacity:0}' }}></style>;
}
return <script src={this.props.jsUrl}></script>;
}
}
AnimeJs.Cacheable = cacheComponent(AnimeJs, 'plugin.animejs', props => {
const { helper, head } = props;
return {
head,
jsUrl: helper.url_for('/js/animation.js')
};
});
module.exports = AnimeJs;
================================================
FILE: layout/plugin/back_to_top.jsx
================================================
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class BackToTop extends Component {
render() {
const { title, jsUrl } = this.props;
return <Fragment>
<a id="back-to-top" title={title} href="javascript:;">
<i class="fas fa-chevron-up"></i>
</a>
<script data-pjax src={jsUrl} defer></script>
</Fragment>;
}
}
BackToTop.Cacheable = cacheComponent(BackToTop, 'plugin.backtotop', props => {
const { helper, head } = props;
if (head) {
return null;
}
return {
title: helper.__('plugin.backtotop'),
jsUrl: helper.url_for('/js/back_to_top.js')
};
});
module.exports = BackToTop;
================================================
FILE: layout/plugin/pjax.jsx
================================================
const { Component, Fragment } = require('inferno');
class Pjax extends Component {
render() {
if (this.props.head) {
return null;
}
const { helper } = this.props;
const { url_for, cdn } = helper;
return <Fragment>
<script src={cdn('pjax', '0.2.8', 'pjax.min.js')}></script>
<script src={url_for('/js/pjax.js')}></script>
</Fragment>;
}
}
module.exports = Pjax;
================================================
FILE: layout/post.jsx
================================================
const { Component } = require('inferno');
const Article = require('./common/article');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
return <Article config={config} page={page} helper={helper} index={false} />;
}
};
================================================
FILE: layout/search/.gitkeep
================================================
================================================
FILE: layout/share/.gitkeep
================================================
================================================
FILE: layout/tag.jsx
================================================
const { Component, Fragment } = require('inferno');
const Index = require('./index');
module.exports = class extends Component {
render() {
const { config, page, helper } = this.props;
const { url_for, _p } = helper;
return <Fragment>
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href={url_for('/tags/')}>{_p('common.tag', Infinity)}</a></li>
<li class="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
</ul>
</nav>
</div>
</div>
<Index config={config} page={page} helper={helper} />
</Fragment>;
}
};
================================================
FILE: layout/tags.jsx
================================================
const { Component } = require('inferno');
const Tags = require('hexo-component-inferno/lib/view/widget/tags');
module.exports = class extends Component {
render() {
const { site, helper } = this.props;
return <Tags.Cacheable site={site} helper={helper} />;
}
};
================================================
FILE: layout/widget/profile.jsx
================================================
const { Component } = require('inferno');
const gravatrHelper = require('hexo-util').gravatar;
const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class Profile extends Component {
renderSocialLinks(links) {
if (!links.length) {
return null;
}
return <div class="level is-mobile is-multiline">
{links.filter(link => typeof link === 'object').map(link => {
return <a class="level-item button is-transparent is-marginless"
target="_blank" rel="me noopener" title={link.name} href={link.url}>
{'icon' in link ? <i class={link.icon}></i> : link.name}
</a>;
})}
</div>;
}
render() {
const {
avatar,
avatarRounded,
author,
authorTitle,
location,
counter,
followLink,
followTitle,
socialLinks
} = this.props;
return <div class="card widget" data-type="profile">
<div class="card-content">
<nav class="level">
<div class="level-item has-text-centered flex-shrink-1">
<div>
<figure class="image is-128x128 mx-auto mb-2">
<img class={'avatar' + (avatarRounded ? ' is-rounded' : '')} src={avatar} alt={author} />
</figure>
{author ? <p class="title is-size-4 is-block" style={{'line-height': 'inherit'}}>{author}</p> : null}
{authorTitle ? <p class="is-size-6 is-block">{authorTitle}</p> : null}
{location ? <p class="is-size-6 is-flex justify-content-center">
<i class="fas fa-map-marker-alt mr-1"></i>
<span>{location}</span>
</p> : null}
</div>
</div>
</nav>
<nav class="level is-mobile">
<div class="level-item has-text-centered is-marginless">
<div>
<p class="heading">{counter.post.title}</p>
<a href={counter.post.url}>
<p class="title">{counter.post.count}</p>
</a>
</div>
</div>
<div class="level-item has-text-centered is-marginless">
<div>
<p class="heading">{counter.category.title}</p>
<a href={counter.category.url}>
<p class="title">{counter.category.count}</p>
</a>
</div>
</div>
<div class="level-item has-text-centered is-marginless">
<div>
<p class="heading">{counter.tag.title}</p>
<a href={counter.tag.url}>
<p class="title">{counter.tag.count}</p>
</a>
</div>
</div>
</nav>
{followLink ? <div class="level">
<a class="level-item button is-primary is-rounded" href={followLink} target="_blank" rel="me noopener">{followTitle}</a>
</div> : null}
{socialLinks ? this.renderSocialLinks(socialLinks) : null}
</div>
</div>;
}
}
Profile.Cacheable = cacheComponent(Profile, 'widget.profile', props => {
const { site, helper, widget } = props;
const {
avatar,
gravatar,
avatar_rounded = false,
author = props.config.author,
author_title,
location,
follow_link,
social_links
} = widget;
const { url_for, _p, __ } = helper;
function getAvatar() {
if (gravatar) {
return gravatrHelper(gravatar, 128);
}
if (avatar) {
return url_for(avatar);
}
return url_for('/img/avatar.png');
}
const postCount = site.posts.length;
const categoryCount = site.categories.filter(category => category.length).length;
const tagCount = site.tags.filter(tag => tag.length).length;
const socialLinks = social_links ? Object.keys(social_links).map(name => {
const link = social_links[name];
if (typeof link === 'string') {
return {
name,
url: url_for(link)
};
}
return {
name,
url: url_for(link.url),
icon: link.icon
};
}) : null;
return {
avatar: getAvatar(),
avatarRounded: avatar_rounded,
author,
authorTitle: author_title,
location,
counter: {
post: {
count: postCount,
title: _p('common.post', postCount),
url: url_for('/archives/')
},
category: {
count: categoryCount,
title: _p('common.category', categoryCount),
url: url_for('/categories/')
},
tag: {
count: tagCount,
title: _p('common.tag', tagCount),
url: url_for('/tags/')
}
},
followLink: follow_link ? url_for(follow_link) : undefined,
followTitle: __('widget.follow'),
socialLinks
};
});
module.exports = Profile;
================================================
FILE: package.json
================================================
{
"name": "hexo-theme-icarus",
"version": "6.1.1",
"author": "ppoffice <ppoffice@users.noreply.github.com>",
"license": "MIT",
"description": "A simple, delicate, and modern theme for Hexo",
"keywords": [
"hexo",
"theme",
"icarus"
],
"homepage": "https://github.com/ppoffice/hexo-theme-icarus",
"repository": "https://github.com/ppoffice/hexo-theme-icarus.git",
"bugs": {
"url": "https://github.com/ppoffice/hexo-theme-icarus/issues"
},
"engines": {
"node": ">=14"
},
"scripts": {
"lint": "eslint --ext .js --ext .jsx --ext .json ."
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-hexo": "^5.0.0",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-react": "^7.33.2"
},
"dependencies": {
"bulma-stylus": "0.8.0",
"deepmerge": "^4.3.1",
"hexo": "^7.1.1",
"hexo-component-inferno": "^3.1.2",
"hexo-log": "^4.1.0",
"hexo-pagination": "^3.0.0",
"hexo-renderer-inferno": "^1.0.2",
"hexo-renderer-stylus": "^3.0.1",
"hexo-util": "^3.2.0",
"inferno": "^8.2.3",
"inferno-create-element": "^8.2.3",
"moment": "^2.30.1",
"semver": "^7.5.4"
}
}
================================================
FILE: scripts/index.js
================================================
/* global hexo */
const createLogger = require('hexo-log');
const logger = createLogger.default();
/**
* Print welcome message
*/
logger.info(`=======================================
██╗ ██████╗ █████╗ ██████╗ ██╗ ██╗███████╗
██║██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝
██║██║ ███████║██████╔╝██║ ██║███████╗
██║██║ ██╔══██║██╔══██╗██║ ██║╚════██║
██║╚██████╗██║ ██║██║ ██║╚██████╔╝███████║
╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
=============================================`);
/**
* Check if all dependencies are installed
*/
require('../include/dependency')(hexo);
/**
* Configuration file checking and migration
*/
require('../include/config')(hexo);
/**
* Register Hexo extensions and remove Hexo filters that could cause OOM
*/
require('../include/register')(hexo);
================================================
FILE: source/css/cyberpunk.styl
================================================
$family-sans-serif ?= 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif
$family-code ?= 'Roboto Mono', monospace, 'Microsoft YaHei'
// shadow and radius
$shadow ?= none
$radius ?= 0
$radius-small ?= 0
// base colors
$white ?= #fff
$white-bis ?= #cdcdcd
$grey ?= #848484
$black ?= #000
$black-bis ?= #050a0e
$orange ?= #ff8e3c
$yellow ?= #fcee09
$green ?= #00ff41
$blue ?= #02d7f2
$purple ?= #9561d2
$red ?= #ff003c
$primary ?= $yellow
$info ?= $blue
$success ?= $green
$warning ?= $orange
$danger ?= $red
// invert colors
$orange-invert ?= #121617
$yellow-invert ?= #121617
$green-invert ?= #121617
$blue-invert ?= #121617
$purple-invert ?= #121617
$red-invert ?= #121617
$primary-invert ?= #121617
$info-invert ?= #121617
$success-invert ?= #121617
$warning-invert ?= #121617
$danger-invert ?= #121617
// derived colors
$scheme-main ?= $black
$link ?= $blue
$link-hover ?= $primary
$text ?= $white-bis
$text-strong ?= $yellow
$body-background-color ?= $scheme-main
$input-color ?= $text
$input-placeholder-color ?= rgba($input-color, .8)
$footer-color ?= $black
$footer-background-color ?= $yellow
$navbar-background-color ?= $yellow
$navbar-item-color ?= $black
$navbar-item-active-color ?= $black
$navbar-item-hover-color ?= $black
$navbar-item-hover-background-color ?= transparent
$navbar-item-margin-v ?= 1.25rem
$navbar-item-margin-h ?= .25rem
$navbar-item-padding-v ?= 0
$navbar-item-padding-h ?= .5rem
$card-background-color ?= transparent
$menu-label-color ?= $blue
$menu-item-hover-color ?= $black
$menu-item-hover-background-color ?= $yellow
$menu-item-active-color ?= $black
$menu-item-active-background-color ?= $yellow
$menu-list-border-left ?= 1px solid $text
$tag-color ?= $black
$tag-background-color ?= $blue
$timeline-fg-line ?= $blue
$timeline-bg-line ?= $body-background-color
$post-navigation-fg ?= $white-bis
$searchbox-bg-container ?= $black-bis
$searchbox-border ?= $blue
$searchbox-bg-input ?= $black-bis
$searchbox-bg-close-hover ?= $black
$searchbox-bg-close-active ?= $searchbox-bg-close-hover
$searchbox-bg-result-item-hover ?= $black
@import 'style'
clip-path(clip)
clip-path: clip
-webkit-clip-path: clip
cut-corner(size)
clip-path(unquote('polygon(' + size + ' 0, 100% 0, 100% calc(100% - ' + size + '), calc(100% - ' + size + ') 100%, 0 100%, 0 ' + size + ')'))
cut-corner-reverse(size)
clip-path(unquote('polygon(0 0, calc(100% - ' + size + ') 0, 100% ' + size + ', 100% 100%, ' + size + ' 100%, 0 calc(100% - ' + size + '), 0 0)'))
cut-corner-top-right(size)
clip-path(unquote('polygon(0 0, calc(100% - ' + size + ') 0, 100% ' + size + ', 100% 100%, 0 100%)'))
cut-corner-bottom-left(size)
clip-path(unquote('polygon(0 0, 100% 0, 100% 100%, ' + size + ' 100%, 0 calc(100% - ' + size + '))'))
cut-corner-bottom-right(size)
clip-path(unquote('polygon(0 0, 100% 0, 100% calc(100% - ' + size + '), calc(100% - ' + size + ') 100%, 0 100%)'))
undercover-before()
position: relative
&:before
content: ''
position: absolute
z-index: -1
top: 0
left: 0
right: 0
bottom: 0
body
counter-reset: card
::selection
color: $black
background: $blue
.card:not(#back-to-top)
position: relative
counter-increment: card
&, .card-content
undercover-before()
&:before
top: -1.2px
left: -1.2px
right: -1.2px
bottom: -1.2px
background-color: $blue
cut-corner-reverse(16px)
&:after
content: 'R' counter(card)
position: absolute
color: $blue
right: 2rem
bottom: -.6em
font-size: .75rem
padding: 0 .25em
background: $body-background-color
.card-image
cut-corner-top-right(16px)
.card-content:before
background-color: $body-background-color
cut-corner-reverse(16px)
.card-image + .card-content:before
cut-corner-bottom-left(16px)
clip-button($color, $color-invert)
&:before
background-color: $color
color: $color-invert
&:hover:before, &.is-hovered:before
background-color: darken($color, 2.5%)
color: $color-invert
&:focus:before, &.is-focused:before
color: $color-invert
&:active:before, &.is-active:before
background-color: darken($color, 5%)
color: $color-invert
&[disabled]:before, fieldset[disabled] &:before
background-color: $color
&.is-inverted
&:before
background-color: $color-invert
color: $color
&:hover:before, &.is-hovered:before
background-color: darken($color-invert, 5%)
&[disabled]:before, fieldset[disabled] &:before
background-color: $color-invert
border-color: transparent
box-shadow: none
color: $color
.button:not(input)
border: none
outline: none
background: transparent !important
undercover-before()
&:before
cut-corner(8px)
// clip-path will cut off overflown content inside a button
// thus we need to use :before pseudo-element to style the buttons
for $name, $pair in $colors
$color = $pair['1']
$color-invert = $pair['2']
&.is-{$name}
clip-button($color, $color-invert)
.field.has-addons
.control:not(:first-child)
.button
cut-corner-bottom-right(8px)
.menu-list a
cut-corner(8px)
.tags.has-addons
.tag:first-child
background: $yellow !important
.tag:last-child
background: $blue !important
.pagination-previous, .pagination-next, .pagination-link
cut-corner(8px)
&:hover
background-color: $blue
&, a
color: $black
.navbar-main
padding-top: 10px
padding-bottom: 30px
&:after
content: ''
position: absolute
left: 0
right: 0
bottom: -2px
background: url('../img/razor-top-black.svg') repeat-x top
height: 40px
.navbar-menu
.navbar-item
&:hover, &.is-active
color: $navbar-background-color
background-color: $body-background-color !important
article.article, article.media
.title a
background-image: linear-gradient(transparent calc(100% - 2px), $text-strong 2px)
background-repeat: no-repeat
background-size: 0 100%
transition: background-size .25s ease-in-out
.title:hover a
background-size: 100% 100%
article.article
.article-more
clip-button($info, $info-invert)
.article-licensing
background: $black-ter
.content
blockquote
background: transparent
border: .5px solid $blue
border-left: 5px solid $blue
.footer
position: relative
&:before
content: ''
position: absolute
left: 0
right: 0
top: -1px
height: 39px
background: url('../img/razor-bottom-black.svg') repeat-x top
& > .container
padding-top: 40px
.timeline .media
&:before
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%)
.searchbox .searchbox-container
border: 1px solid $blue
.searchbox-body
border-bottom: 1px solid $searchbox-border
li:last-child .searchbox-result-section
border-bottom: none
.searchbox-result-item
em
color: $black
#back-to-top
color: $black
background: $blue
margin-top: 45px
cut-corner(8px)
.cc-window, .cc-revoke
border-radius: 0 !important
.cc-window
&:not(.cc-banner)
border: 1px solid $blue
&.cc-theme-classic, &.cc-theme-block
.cc-compliance > .cc-btn
border-radius: 0
&.cc-banner
.cc-compliance > .cc-btn
background-color: $blue
&:hover, &:focus
background-color: darken($blue, 2.5%)
================================================
FILE: source/css/default.styl
================================================
@import 'style'
================================================
FILE: source/css/style.styl
================================================
// Base CSS framework
@import '../../include/style/base'
// Helper classes & mixins
@import '../../include/style/helper'
// Icarus components
@import '../../include/style/button'
@import '../../include/style/card'
@import '../../include/style/article'
@import '../../include/style/navbar'
@import '../../include/style/footer'
@import '../../include/style/pagination'
@import '../../include/style/timeline'
@import '../../include/style/search'
@import '../../include/style/codeblock'
@import '../../include/style/widget'
@import '../../include/style/donate'
@import '../../include/style/plugin'
@import '../../include/style/responsive'
================================================
FILE: source/js/.eslintrc.json
================================================
{
"extends": "../../.eslintrc.json",
"env": {
"browser": true,
"jquery": true,
"node": false
}
}
================================================
FILE: source/js/animation.js
================================================
(function() {
function $() {
return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
}
$('body > .navbar, body > .section, body > .footer').forEach(element => {
element.style.transition = '0s';
element.style.opacity = '0';
});
document.querySelector('body > .navbar').style.transform = 'translateY(-100px)';
[
'.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
'.column-left > .card, .column-right-shadow > .card',
'.column-right > .card'
].forEach(selector => {
$(selector).forEach(element => {
element.style.transition = '0s';
element.style.opacity = '0';
element.style.transform = 'scale(0.8)';
element.style.transformOrigin = 'center top';
});
});
// disable jump to location.hash
if (window.location.hash) {
window.scrollTo(0, 0);
setTimeout(() => window.scrollTo(0, 0));
}
setTimeout(() => {
$('body > .navbar, body > .section, body > .footer').forEach(element => {
element.style.opacity = '1';
element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
});
document.querySelector('body > .navbar').style.transform = 'translateY(0)';
let i = 1;
[
'.column-main > .card, .column-main > .pagination, .column-main > .post-navigation',
'.column-left > .card, .column-right-shadow > .card',
'.column-right > .card'
].forEach(selector => {
$(selector).forEach(element => {
setTimeout(() => {
element.style.opacity = '1';
element.style.transform = '';
element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
}, i * 100);
i++;
});
});
// jump to location.hash
if (window.location.hash) {
setTimeout(() => {
const id = '#' + CSS.escape(window.location.hash.substring(1));
const target = document.querySelector(id);
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
}
}, i * 100);
}
});
}());
================================================
FILE: source/js/back_to_top.js
================================================
$(document).ready(() => {
const $button = $('#back-to-top');
const $footer = $('footer.footer');
const $mainColumn = $('.column-main');
const $leftSidebar = $('.column-left');
const $rightSidebar = $('.column-right');
let lastScrollTop = 0;
const rightMargin = 20;
const bottomMargin = 20;
let lastState = null;
const state = {
base: {
classname: 'card has-text-centered',
left: '',
width: 64,
bottom: bottomMargin
}
};
state['desktop-hidden'] = Object.assign({}, state.base, {
classname: state.base.classname + ' rise-up'
});
state['desktop-visible'] = Object.assign({}, state['desktop-hidden'], {
classname: state['desktop-hidden'].classname + ' fade-in'
});
state['desktop-dock'] = Object.assign({}, state['desktop-visible'], {
classname: state['desktop-visible'].classname + ' fade-in is-rounded',
width: 40
});
state['mobile-hidden'] = Object.assign({}, state.base, {
classname: state.base.classname + ' fade-in',
right: rightMargin
});
state['mobile-visible'] = Object.assign({}, state['mobile-hidden'], {
classname: state['mobile-hidden'].classname + ' rise-up'
});
function isStateEquals(prev, next) {
return ![].concat(Object.keys(prev), Object.keys(next)).some(key => {
return !Object.prototype.hasOwnProperty.call(prev, key)
|| !Object.prototype.hasOwnProperty.call(next, key)
|| next[key] !== prev[key];
});
}
function applyState(state) {
if (lastState !== null && isStateEquals(lastState, state)) {
return;
}
$button.attr('class', state.classname);
for (const prop in state) {
if (prop === 'classname') {
continue;
}
$button.css(prop, state[prop]);
}
lastState = state;
}
function isDesktop() {
return window.innerWidth >= 1078;
}
function isTablet() {
return window.innerWidth >= 768 && !isDesktop();
}
function isScrollUp() {
return $(window).scrollTop() < lastScrollTop && $(window).scrollTop() > 0;
}
function hasLeftSidebar() {
return $leftSidebar.length > 0;
}
function hasRightSidebar() {
return $rightSidebar.length > 0;
}
function getRightSidebarBottom() {
if (!hasRightSidebar()) {
return 0;
}
return Math.max.apply(null, $rightSidebar.find('.widget').map(function() {
return $(this).offset().top + $(this).outerHeight(true);
}));
}
function getScrollTop() {
return $(window).scrollTop();
}
function getScrollBottom() {
return $(window).scrollTop() + $(window).height();
}
function getButtonWidth() {
return $button.outerWidth(true);
}
function getButtonHeight() {
return $button.outerHeight(true);
}
function updateScrollTop() {
lastScrollTop = $(window).scrollTop();
}
function update() {
// desktop mode or tablet mode with only right sidebar enabled
if (isDesktop() || (isTablet() && !hasLeftSidebar() && hasRightSidebar())) {
let nextState;
const padding = ($mainColumn.outerWidth() - $mainColumn.width()) / 2;
const maxLeft = $(window).width() - getButtonWidth() - rightMargin;
const maxBottom = $footer.offset().top + (getButtonHeight() / 2) + bottomMargin;
if (getScrollTop() === 0 || getScrollBottom() < getRightSidebarBottom() + padding + getButtonHeight()) {
nextState = state['desktop-hidden'];
} else if (getScrollBottom() < maxBottom) {
nextState = state['desktop-visible'];
} else {
nextState = Object.assign({}, state['desktop-dock'], {
bottom: getScrollBottom() - maxBottom + bottomMargin
});
}
const left = $mainColumn.offset().left + $mainColumn.outerWidth() + padding;
nextState = Object.assign({}, nextState, {
left: Math.min(left, maxLeft)
});
applyState(nextState);
} else {
// mobile and tablet mode
if (!isScrollUp()) {
applyState(state['mobile-hidden']);
} else {
applyState(state['mobile-visible']);
}
updateScrollTop();
}
}
update();
$(window).resize(update);
$(window).scroll(update);
$('#back-to-top').on('click', () => {
if (CSS && CSS.supports && CSS.supports('(scroll-behavior: smooth)')) {
window.scroll({ top: 0, behavior: 'smooth' });
} else {
$('body, html').animate({ scrollTop: 0 }, 400);
}
});
});
================================================
FILE: source/js/column.js
================================================
(function() {
function $() {
return Array.prototype.slice.call(document.querySelectorAll.apply(document, arguments));
}
// copy widgets in the right column, when exist, to the bottom of the left column
if ($('.columns .column-right').length && $('.columns .column-right-shadow').length && !$('.columns .column-right-shadow')[0].children.length) {
for (const child of $('.columns .column-right')[0].children) {
$('.columns .column-right-shadow')[0].append(child.cloneNode(true));
}
}
}());
================================================
FILE: source/js/main.js
================================================
/* eslint-disable node/no-unsupported-features/node-builtins */
(function($, moment, ClipboardJS, config) {
$('.article img:not(".not-gallery-item")').each(function() {
// wrap images with link and add caption if possible
if ($(this).parent('a').length === 0) {
$(this).wrap('<a class="gallery-item" href="' + $(this).attr('src') + '"></a>');
if (this.alt) {
$(this).after('<p class="has-text-centered is-size-6 caption">' + this.alt + '</p>');
}
}
});
if (typeof $.fn.lightGallery === 'function') {
$('.article').lightGallery({ selector: '.gallery-item' });
}
if (typeof $.fn.justifiedGallery === 'function') {
if ($('.justified-gallery > p > .gallery-item').length) {
$('.justified-gallery > p > .gallery-item').unwrap();
}
$('.justified-gallery').justifiedGallery();
}
if (typeof moment === 'function') {
$('.article-meta time').each(function() {
$(this).text(moment($(this).attr('datetime')).fromNow());
});
}
$('.article > .content > table').each(function() {
if ($(this).width() > $(this).parent().width()) {
$(this).wrap('<div class="table-overflow"></div>');
}
});
function adjustNavbar() {
const navbarWidth = $('.navbar-main .navbar-start').outerWidth() + $('.navbar-main .navbar-end').outerWidth();
if ($(document).outerWidth() < navbarWidth) {
$('.navbar-main .navbar-menu').addClass('justify-content-start');
} else {
$('.navbar-main .navbar-menu').removeClass('justify-content-start');
}
}
adjustNavbar();
$(window).resize(adjustNavbar);
function toggleFold(codeBlock, isFolded) {
const $toggle = $(codeBlock).find('.fold i');
!isFolded ? $(codeBlock).removeClass('folded') : $(codeBlock).addClass('folded');
!isFolded ? $toggle.removeClass('fa-angle-right') : $toggle.removeClass('fa-angle-down');
!isFolded ? $toggle.addClass('fa-angle-down') : $toggle.addClass('fa-angle-right');
}
function createFoldButton(fold) {
return '<span class="fold">' + (fold === 'unfolded' ? '<i class="fas fa-angle-down"></i>' : '<i class="fas fa-angle-right"></i>') + '</span>';
}
$('figure.highlight table').wrap('<div class="highlight-body">');
if (typeof config !== 'undefined'
&& typeof config.article !== 'undefined'
&& typeof config.article.highlight !== 'undefined') {
$('figure.highlight').addClass('hljs');
$('figure.highlight .code .line span').each(function() {
const classes = $(this).attr('class').split(/\s+/);
for (const cls of classes) {
$(this).addClass('hljs-' + cls);
$(this).removeClass(cls);
}
});
const clipboard = config.article.highlight.clipboard;
const fold = config.article.highlight.fold.trim();
$('figure.highlight').each(function() {
if ($(this).find('figcaption').length) {
$(this).find('figcaption').addClass('level is-mobile');
$(this).find('figcaption').append('<div class="level-left">');
$(this).find('figcaption').append('<div class="level-right">');
$(this).find('figcaption div.level-left').append($(this).find('figcaption').find('span'));
$(this).find('figcaption div.level-right').append($(this).find('figcaption').find('a'));
} else {
if (clipboard || fold) {
$(this).prepend('<figcaption class="level is-mobile"><div class="level-left"></div><div class="level-right"></div></figcaption>');
}
}
});
if (typeof ClipboardJS !== 'undefined' && clipboard) {
$('figure.highlight').each(function() {
const id = 'code-' + Date.now() + (Math.random() * 1000 | 0);
const button = '<a href="javascript:;" class="copy" title="Copy" data-clipboard-target="#' + id + ' .code"><i class="fas fa-copy"></i></a>';
$(this).attr('id', id);
$(this).find('figcaption div.level-right').append(button);
});
gitextract_bspt8wyp/
├── .eslintignore
├── .eslintrc.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── Bug反馈.md
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ ├── feature_request.md
│ │ └── 功能建议.md
│ ├── PULL_REQUEST_TEMPLATE/
│ │ └── pull_request_template.md
│ ├── dependabot.yml
│ ├── stale.yml
│ └── workflows/
│ ├── github-release.yml
│ ├── lint.yml
│ ├── npm-publish.yml
│ └── test.yml
├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── include/
│ ├── config.js
│ ├── dependency.js
│ ├── migration/
│ │ ├── head.js
│ │ ├── v2_v3.js
│ │ ├── v3_v4.js
│ │ ├── v4_v5.js
│ │ └── v5_v5.1.js
│ ├── register.js
│ ├── schema/
│ │ ├── comment/
│ │ │ └── .gitkeep
│ │ ├── common/
│ │ │ ├── article.json
│ │ │ ├── comment.json
│ │ │ ├── donates.json
│ │ │ ├── footer.json
│ │ │ ├── head.json
│ │ │ ├── navbar.json
│ │ │ ├── plugins.json
│ │ │ ├── providers.json
│ │ │ ├── search.json
│ │ │ ├── share.json
│ │ │ ├── sidebar.json
│ │ │ └── widgets.json
│ │ ├── config.json
│ │ ├── donate/
│ │ │ └── .gitkeep
│ │ ├── misc/
│ │ │ └── .gitkeep
│ │ ├── plugin/
│ │ │ ├── animejs.json
│ │ │ ├── back_to_top.json
│ │ │ └── pjax.json
│ │ ├── search/
│ │ │ └── .gitkeep
│ │ ├── share/
│ │ │ └── .gitkeep
│ │ └── widget/
│ │ └── profile.json
│ ├── style/
│ │ ├── article.styl
│ │ ├── base.styl
│ │ ├── button.styl
│ │ ├── card.styl
│ │ ├── codeblock.styl
│ │ ├── donate.styl
│ │ ├── footer.styl
│ │ ├── helper.styl
│ │ ├── navbar.styl
│ │ ├── pagination.styl
│ │ ├── plugin.styl
│ │ ├── responsive.styl
│ │ ├── search.styl
│ │ ├── timeline.styl
│ │ └── widget.styl
│ └── util/
│ └── console.js
├── languages/
│ ├── de.yml
│ ├── en.yml
│ ├── es.yml
│ ├── fr.yml
│ ├── id.yml
│ ├── it.yml
│ ├── ja.yml
│ ├── ko.yml
│ ├── pl.yml
│ ├── pt-BR.yml
│ ├── ru.yml
│ ├── sv.yml
│ ├── tk.yml
│ ├── tr.yml
│ ├── vn.yml
│ ├── zh-CN.yml
│ └── zh-TW.yml
├── layout/
│ ├── archive.jsx
│ ├── categories.jsx
│ ├── category.jsx
│ ├── comment/
│ │ └── .gitkeep
│ ├── common/
│ │ ├── article.jsx
│ │ ├── comment.jsx
│ │ ├── donates.jsx
│ │ ├── footer.jsx
│ │ ├── head.jsx
│ │ ├── navbar.jsx
│ │ ├── plugins.jsx
│ │ ├── scripts.jsx
│ │ ├── search.jsx
│ │ ├── share.jsx
│ │ └── widgets.jsx
│ ├── donate/
│ │ └── .gitkeep
│ ├── index.jsx
│ ├── layout.jsx
│ ├── misc/
│ │ └── .gitkeep
│ ├── page.jsx
│ ├── plugin/
│ │ ├── animejs.jsx
│ │ ├── back_to_top.jsx
│ │ └── pjax.jsx
│ ├── post.jsx
│ ├── search/
│ │ └── .gitkeep
│ ├── share/
│ │ └── .gitkeep
│ ├── tag.jsx
│ ├── tags.jsx
│ └── widget/
│ └── profile.jsx
├── package.json
├── scripts/
│ └── index.js
└── source/
├── css/
│ ├── cyberpunk.styl
│ ├── default.styl
│ └── style.styl
└── js/
├── .eslintrc.json
├── animation.js
├── back_to_top.js
├── column.js
├── main.js
└── pjax.js
SYMBOL INDEX (76 symbols across 35 files)
FILE: include/config.js
function loadThemeConfig (line 14) | function loadThemeConfig(hexo, cfgPaths) {
function generateThemeConfigFile (line 20) | function generateThemeConfigFile(schema, cfgPath) {
function hashConfigFile (line 25) | function hashConfigFile(cfgPath) {
function checkConfig (line 30) | function checkConfig(hexo) {
FILE: include/dependency.js
function checkDependency (line 10) | function checkDependency(name, reqVer) {
FILE: include/migration/v2_v3.js
method constructor (line 8) | constructor() {
method upgrade (line 12) | upgrade(config) {
FILE: include/migration/v3_v4.js
method constructor (line 4) | constructor() {
method upgrade (line 8) | upgrade(config) {
FILE: include/migration/v4_v5.js
method constructor (line 4) | constructor() {
method upgrade (line 8) | upgrade(config) {
FILE: include/migration/v5_v5.1.js
method constructor (line 4) | constructor() {
method upgrade (line 8) | upgrade(config) {
FILE: include/util/console.js
method get (line 7) | get(obj, prop) {
FILE: layout/archive.jsx
method render (line 8) | render() {
FILE: layout/categories.jsx
method render (line 5) | render() {
FILE: layout/category.jsx
method render (line 5) | render() {
FILE: layout/common/article.jsx
function getWordCount (line 12) | function getWordCount(content) {
method url_for (line 68) | url_for(category.path)}>{category.name}
method url_for (line 102) | url_for(tag.path)}>{tag.name}
FILE: layout/common/comment.jsx
method render (line 8) | render() {
FILE: layout/common/donates.jsx
method render (line 8) | render() {
FILE: layout/common/head.jsx
function getPageTitle (line 8) | function getPageTitle(page, siteTitle, helper) {
method render (line 32) | render() {
FILE: layout/common/navbar.jsx
function isSameLink (line 5) | function isSameLink(a, b) {
class Navbar (line 16) | class Navbar extends Component {
method render (line 17) | render() {
FILE: layout/common/plugins.jsx
method render (line 8) | render() {
FILE: layout/common/scripts.jsx
method render (line 6) | render() {
FILE: layout/common/search.jsx
method render (line 8) | render() {
FILE: layout/common/share.jsx
method render (line 8) | render() {
FILE: layout/common/widgets.jsx
function formatWidgets (line 8) | function formatWidgets(widgets) {
function hasColumn (line 24) | function hasColumn(widgets, position, config, page) {
function getColumnCount (line 37) | function getColumnCount(widgets, config, page) {
function getColumnSizeClass (line 41) | function getColumnSizeClass(columnCount) {
function getColumnVisibilityClass (line 51) | function getColumnVisibilityClass(columnCount, position) {
function getColumnOrderClass (line 58) | function getColumnOrderClass(position) {
function isColumnSticky (line 62) | function isColumnSticky(config, position) {
class Widgets (line 68) | class Widgets extends Component {
method render (line 69) | render() {
FILE: layout/index.jsx
method render (line 6) | render() {
FILE: layout/layout.jsx
method render (line 11) | render() {
FILE: layout/page.jsx
method render (line 5) | render() {
FILE: layout/plugin/animejs.jsx
class AnimeJs (line 4) | class AnimeJs extends Component {
method render (line 5) | render() {
FILE: layout/plugin/back_to_top.jsx
class BackToTop (line 4) | class BackToTop extends Component {
method render (line 5) | render() {
FILE: layout/plugin/pjax.jsx
class Pjax (line 3) | class Pjax extends Component {
method render (line 4) | render() {
FILE: layout/post.jsx
method render (line 5) | render() {
FILE: layout/tag.jsx
method render (line 5) | render() {
FILE: layout/tags.jsx
method render (line 5) | render() {
FILE: layout/widget/profile.jsx
class Profile (line 5) | class Profile extends Component {
method renderSocialLinks (line 6) | renderSocialLinks(links) {
function getAvatar (line 98) | function getAvatar() {
FILE: source/js/animation.js
function $ (line 2) | function $() {
FILE: source/js/back_to_top.js
function isStateEquals (line 37) | function isStateEquals(prev, next) {
function applyState (line 45) | function applyState(state) {
function isDesktop (line 59) | function isDesktop() {
function isTablet (line 63) | function isTablet() {
function isScrollUp (line 67) | function isScrollUp() {
function hasLeftSidebar (line 71) | function hasLeftSidebar() {
function hasRightSidebar (line 75) | function hasRightSidebar() {
function getRightSidebarBottom (line 79) | function getRightSidebarBottom() {
function getScrollTop (line 88) | function getScrollTop() {
function getScrollBottom (line 92) | function getScrollBottom() {
function getButtonWidth (line 96) | function getButtonWidth() {
function getButtonHeight (line 100) | function getButtonHeight() {
function updateScrollTop (line 104) | function updateScrollTop() {
function update (line 108) | function update() {
FILE: source/js/column.js
function $ (line 2) | function $() {
FILE: source/js/main.js
function adjustNavbar (line 35) | function adjustNavbar() {
function toggleFold (line 46) | function toggleFold(codeBlock, isFolded) {
function createFoldButton (line 53) | function createFoldButton(fold) {
function toggleToc (line 130) | function toggleToc() { // eslint-disable-line no-inner-declarations
FILE: source/js/pjax.js
function initPjax (line 5) | function initPjax() {
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (202K chars).
[
{
"path": ".eslintignore",
"chars": 13,
"preview": "node_modules/"
},
{
"path": ".eslintrc.json",
"chars": 1063,
"preview": "{\n \"extends\": [\n \"hexo\",\n \"plugin:react/recommended\",\n \"plugin:json/recommended\"\n ],\n \"settings\": {\n \"nod"
},
{
"path": ".github/ISSUE_TEMPLATE/Bug反馈.md",
"chars": 827,
"preview": "---\nname: Bug反馈\nabout: 请按照模板填写Bug反馈,否则你的Issue可能会被直接关闭。\ntitle: [Bug] 问题概述\nlabels: ''\nassignees: ''\n\n---\n\n> 确保你在提交Bug反馈之前仔"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 1395,
"preview": "---\nname: Bug Report\nabout: Please follow this template if you are reporting a bug, or your issue may be closed without "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 1075,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: GitHub Discussions\n url: https://github.com/ppoffice/hexo-theme-"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 1022,
"preview": "---\nname: Feature Request\nabout: Please follow this template if you are requesting a new feature, or your issue may be c"
},
{
"path": ".github/ISSUE_TEMPLATE/功能建议.md",
"chars": 539,
"preview": "---\nname: 功能建议\nabout: 请按照模板填写功能建议,否则你的Issue可能会被直接关闭。\ntitle: [FEAT] 功能建议概述\nlabels: ''\nassignees: ''\n\n---\n\n> 确保你在提交功能建议之前仔"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
"chars": 1189,
"preview": "---\nname: Pull Request\nabout: Suggest a code change to this project.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Note 0**"
},
{
"path": ".github/dependabot.yml",
"chars": 106,
"preview": "version: 2\nupdates:\n - package-ecosystem: 'npm'\n directory: '/'\n schedule:\n interval: 'daily'\n"
},
{
"path": ".github/stale.yml",
"chars": 935,
"preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 14\n# Number of days of inactivity before a "
},
{
"path": ".github/workflows/github-release.yml",
"chars": 357,
"preview": "name: GitHub Release\n\non:\n push:\n tags:\n - '*'\n\njobs:\n publish:\n runs-on: ubuntu-latest\n permissions:\n "
},
{
"path": ".github/workflows/lint.yml",
"chars": 264,
"preview": "name: Code Linting\n\non: [push, pull_request]\n\njobs:\n lint:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/"
},
{
"path": ".github/workflows/npm-publish.yml",
"chars": 370,
"preview": "name: Node.js Package\n\non:\n release:\n types: [published]\n\njobs:\n publish:\n runs-on: ubuntu-latest\n steps:\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 1176,
"preview": "name: Test\n\non: [push, pull_request]\n\njobs:\n test:\n runs-on: ubuntu-latest\n strategy:\n matrix:\n node-"
},
{
"path": ".gitignore",
"chars": 1759,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs."
},
{
"path": ".npmignore",
"chars": 60,
"preview": ".github/\n.eslintignore\n.eslintrc.json\n.travis.yml\nyarn.lock\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 1915,
"preview": "# Contributing Guidelines\n\n## Code styles\n\nPlease refer to the [.eslintrc.json](https://github.com/ppoffice/hexo-theme-i"
},
{
"path": "LICENSE",
"chars": 1075,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2020 PPOffice\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "README.md",
"chars": 5816,
"preview": "<p align=\"center\" class=\"mb-2\">\n<img class=\"not-gallery-item\" height=\"48\" src=\"https://ppoffice.github.io/hexo-theme-ica"
},
{
"path": "include/config.js",
"chars": 5021,
"preview": "/* eslint no-process-exit: \"off\" */\nconst fs = require('fs');\nconst path = require('path');\nconst util = require('util')"
},
{
"path": "include/dependency.js",
"chars": 1532,
"preview": "/* eslint no-process-exit: \"off\" */\nconst semver = require('semver');\nconst createLogger = require('hexo-log');\nconst pa"
},
{
"path": "include/migration/head.js",
"chars": 39,
"preview": "module.exports = require('./v5_v5.1');\n"
},
{
"path": "include/migration/v2_v3.js",
"chars": 3857,
"preview": "const createLogger = require('hexo-log');\nconst deepmerge = require('deepmerge');\nconst Migration = require('hexo-compon"
},
{
"path": "include/migration/v3_v4.js",
"chars": 340,
"preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
},
{
"path": "include/migration/v4_v5.js",
"chars": 235,
"preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
},
{
"path": "include/migration/v5_v5.1.js",
"chars": 955,
"preview": "const Migration = require('hexo-component-inferno/lib/core/migrate').Migration;\n\nmodule.exports = class extends Migratio"
},
{
"path": "include/register.js",
"chars": 994,
"preview": "const createLogger = require('hexo-log');\n\nconst logger = createLogger.default();\n\nmodule.exports = hexo => {\n logger"
},
{
"path": "include/schema/comment/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "include/schema/common/article.json",
"chars": 2668,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/article.json\",\n \"description\": \"Artic"
},
{
"path": "include/schema/common/comment.json",
"chars": 1106,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/comment.json\",\n \"description\": \"Comme"
},
{
"path": "include/schema/common/donates.json",
"chars": 775,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/donates.json\",\n \"description\": \"Donat"
},
{
"path": "include/schema/common/footer.json",
"chars": 1380,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/footer.json\",\n \"description\": \"Page f"
},
{
"path": "include/schema/common/head.json",
"chars": 858,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/head.json\",\n \"description\": \"Page met"
},
{
"path": "include/schema/common/navbar.json",
"chars": 1246,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/navbar.json\",\n \"description\": \"Page t"
},
{
"path": "include/schema/common/plugins.json",
"chars": 1656,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/plugins.json\",\n \"description\": \"Plugi"
},
{
"path": "include/schema/common/providers.json",
"chars": 929,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/providers.json\",\n \"description\": \"CDN"
},
{
"path": "include/schema/common/search.json",
"chars": 518,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/search.json\",\n \"description\": \"Search"
},
{
"path": "include/schema/common/share.json",
"chars": 576,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/share.json\",\n \"description\": \"Share p"
},
{
"path": "include/schema/common/sidebar.json",
"chars": 1021,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/sidebar.json\",\n \"description\": \"Sideb"
},
{
"path": "include/schema/common/widgets.json",
"chars": 1376,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/common/widgets.json\",\n \"description\": \"Sideb"
},
{
"path": "include/schema/config.json",
"chars": 2044,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/config.json\",\n \"description\": \"The configura"
},
{
"path": "include/schema/donate/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "include/schema/misc/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "include/schema/plugin/animejs.json",
"chars": 192,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/plugin/animejs.json\",\n \"description\": \"Enabl"
},
{
"path": "include/schema/plugin/back_to_top.json",
"chars": 197,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/plugin/back_to_top.json\",\n \"description\": \"S"
},
{
"path": "include/schema/plugin/pjax.json",
"chars": 176,
"preview": "{\r\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n \"$id\": \"/plugin/pjax.json\",\r\n \"description\": \"Enabl"
},
{
"path": "include/schema/search/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "include/schema/share/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "include/schema/widget/profile.json",
"chars": 2756,
"preview": "{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"/widget/profile.json\",\n \"description\": \"Profi"
},
{
"path": "include/style/article.styl",
"chars": 3977,
"preview": "/* ---------------------------------\n * Article Summary and Content\n * --------------------------------- */\n$article-"
},
{
"path": "include/style/base.styl",
"chars": 2506,
"preview": "bulma-stylus-root = '../../../../node_modules/bulma-stylus/stylus'\n\n/* ---------------------------------\n * Override B"
},
{
"path": "include/style/button.styl",
"chars": 217,
"preview": "/* ---------------------------------\n * Buttons\n * --------------------------------- */\n.button\n &.is-tran"
},
{
"path": "include/style/card.styl",
"chars": 423,
"preview": "/* ---------------------------------\n * Card\n * --------------------------------- */\n.card\n overflow: vi"
},
{
"path": "include/style/codeblock.styl",
"chars": 2144,
"preview": "/* ---------------------------------\n * Code Highlight\n * --------------------------------- */\n$codeblock-capti"
},
{
"path": "include/style/donate.styl",
"chars": 1448,
"preview": "/* ---------------------------------\n * Donate Buttons\n * --------------------------------- */\n$donate-qrcode-m"
},
{
"path": "include/style/footer.styl",
"chars": 425,
"preview": "/* ---------------------------------\n * Page Footer\n * --------------------------------- */\nfooter.footer\n "
},
{
"path": "include/style/helper.styl",
"chars": 3021,
"preview": "/* ---------------------------------\n * Spacing helpers\n * --------------------------------- */\n$spacer ?= 1rem"
},
{
"path": "include/style/navbar.styl",
"chars": 1364,
"preview": "/* ---------------------------------\n * Top Navigation\n * --------------------------------- */\n$navbar-item-pa"
},
{
"path": "include/style/pagination.styl",
"chars": 867,
"preview": "/* ---------------------------------\n * Pagination and Post Navigation\n * --------------------------------- */\n$paginat"
},
{
"path": "include/style/plugin.styl",
"chars": 2995,
"preview": "/* ---------------------------------\n * Back to Top Button\n * --------------------------------- */\n#back-to-top\n "
},
{
"path": "include/style/responsive.styl",
"chars": 794,
"preview": "/* ---------------------------------\n * Responsive Layout\n * --------------------------------- */\n+widescreen()\n"
},
{
"path": "include/style/search.styl",
"chars": 5860,
"preview": "/* ---------------------------------\n * Search Box\n * --------------------------------- */\n// container sizes\n"
},
{
"path": "include/style/timeline.styl",
"chars": 1059,
"preview": "/* ---------------------------------\n * Archive Timeline\n * --------------------------------- */\n$timeline-fg-l"
},
{
"path": "include/style/widget.styl",
"chars": 1315,
"preview": ".widget\n .menu-list\n li\n ul\n margin-right: 0\n\n .level\n margin-bott"
},
{
"path": "include/util/console.js",
"chars": 350,
"preview": "let chalk;\ntry {\n chalk = require('chalk'); // eslint-disable-line node/no-extraneous-require\n} catch (e) { }\n\nmodule"
},
{
"path": "languages/de.yml",
"chars": 1702,
"preview": "common:\n archive:\n one: 'Archiv'\n other: 'Archive'\n category:\n one: 'Kategorie'\n other"
},
{
"path": "languages/en.yml",
"chars": 1611,
"preview": "common:\n archive:\n one: 'Archive'\n other: 'Archives'\n category:\n one: 'Category'\n othe"
},
{
"path": "languages/es.yml",
"chars": 1759,
"preview": "#By SrWoOoW\ncommon:\n archive:\n one: 'Archivo'\n other: 'Archivos'\n category:\n one: 'Categoría'"
},
{
"path": "languages/fr.yml",
"chars": 1760,
"preview": "common:\n archive:\n one: 'Archive'\n other: 'Archives'\n category:\n one: 'Catégorie'\n oth"
},
{
"path": "languages/id.yml",
"chars": 1714,
"preview": "common:\n archive:\n one: 'Arsip'\n other: 'Arsip'\n category:\n one: 'Kategori'\n other: 'K"
},
{
"path": "languages/it.yml",
"chars": 1701,
"preview": "common:\n archive:\n one: 'Archivio'\n other: 'Archivi'\n category:\n one: 'Categoria'\n oth"
},
{
"path": "languages/ja.yml",
"chars": 1398,
"preview": "common:\n archive:\n one: 'アーカイブ'\n other: 'アーカイブ'\n category:\n one: 'カテゴリ'\n other: 'カテゴリ'"
},
{
"path": "languages/ko.yml",
"chars": 1425,
"preview": "common:\n archive:\n one: '아카이브'\n other: '아카이브'\n category:\n one: '카테고리'\n other: '카테고리'\n "
},
{
"path": "languages/pl.yml",
"chars": 1733,
"preview": "common:\n archive:\n one: 'Archiwum'\n other: 'Archiwum'\n category:\n one: 'Kategoria'\n ot"
},
{
"path": "languages/pt-BR.yml",
"chars": 1686,
"preview": "common:\n archive:\n one: 'Arquivo'\n other: 'Arquivos'\n category:\n one: 'Categoria'\n oth"
},
{
"path": "languages/ru.yml",
"chars": 1726,
"preview": "common:\n archive:\n one: 'архив'\n other: 'архивы'\n category:\n one: 'категории'\n other: "
},
{
"path": "languages/sv.yml",
"chars": 1693,
"preview": "common:\n archive:\n one: 'Arkiv'\n other: 'Arkiv'\n category:\n one: 'Kategori'\n other: 'K"
},
{
"path": "languages/tk.yml",
"chars": 1580,
"preview": "common:\n archive:\n one: 'Arhiw'\n other: 'Arhiwler'\n category:\n one: 'Bölüm'\n other: 'B"
},
{
"path": "languages/tr.yml",
"chars": 1718,
"preview": "common:\n archive:\n one: 'Arşiv'\n other: 'Arşivler'\n category:\n one: 'Kategori'\n other:"
},
{
"path": "languages/vn.yml",
"chars": 1655,
"preview": "common:\n archive:\n one: 'Lưu trữ'\n other: 'Lưu trữ'\n category:\n one: 'Thể loại'\n other"
},
{
"path": "languages/zh-CN.yml",
"chars": 1273,
"preview": "common:\n archive:\n one: '归档'\n other: '归档'\n category:\n one: '分类'\n other: '分类'\n tag:\n"
},
{
"path": "languages/zh-TW.yml",
"chars": 1285,
"preview": "common:\n archive:\n one: '彙整'\n other: '彙整'\n category:\n one: '分類'\n other: '分類'\n tag:\n"
},
{
"path": "layout/archive.jsx",
"chars": 2733,
"preview": "const moment = require('moment');\nconst { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require"
},
{
"path": "layout/categories.jsx",
"chars": 324,
"preview": "const { Component } = require('inferno');\nconst Categories = require('hexo-component-inferno/lib/view/widget/categories'"
},
{
"path": "layout/category.jsx",
"chars": 1043,
"preview": "const { Component, Fragment } = require('inferno');\nconst Index = require('./index');\n\nmodule.exports = class extends Co"
},
{
"path": "layout/comment/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "layout/common/article.jsx",
"chars": 8188,
"preview": "const moment = require('moment');\nconst { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require"
},
{
"path": "layout/common/comment.jsx",
"chars": 1178,
"preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
},
{
"path": "layout/common/donates.jsx",
"chars": 1412,
"preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
},
{
"path": "layout/common/footer.jsx",
"chars": 3651,
"preview": "const { Component } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/cache');\n\n"
},
{
"path": "layout/common/head.jsx",
"chars": 8256,
"preview": "const { Component } = require('inferno');\nconst MetaTags = require('hexo-component-inferno/lib/view/misc/meta');\nconst W"
},
{
"path": "layout/common/navbar.jsx",
"chars": 4414,
"preview": "const { Component, Fragment } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/"
},
{
"path": "layout/common/plugins.jsx",
"chars": 1054,
"preview": "const createLogger = require('hexo-log');\nconst { Component, Fragment } = require('inferno');\nconst view = require('hexo"
},
{
"path": "layout/common/scripts.jsx",
"chars": 1833,
"preview": "const { Component, Fragment } = require('inferno');\nconst { toMomentLocale } = require('hexo/dist/plugins/helper/date');"
},
{
"path": "layout/common/search.jsx",
"chars": 779,
"preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
},
{
"path": "layout/common/share.jsx",
"chars": 789,
"preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
},
{
"path": "layout/common/widgets.jsx",
"chars": 3815,
"preview": "const createLogger = require('hexo-log');\nconst { Component } = require('inferno');\nconst view = require('hexo-component"
},
{
"path": "layout/donate/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "layout/index.jsx",
"chars": 822,
"preview": "const { Component, Fragment } = require('inferno');\nconst Paginator = require('hexo-component-inferno/lib/view/misc/pagi"
},
{
"path": "layout/layout.jsx",
"chars": 2146,
"preview": "const { Component } = require('inferno');\nconst classname = require('hexo-component-inferno/lib/util/classname');\nconst "
},
{
"path": "layout/misc/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "layout/page.jsx",
"chars": 295,
"preview": "const { Component } = require('inferno');\nconst Article = require('./common/article');\n\nmodule.exports = class extends C"
},
{
"path": "layout/plugin/animejs.jsx",
"chars": 628,
"preview": "const { Component } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/cache');\n\n"
},
{
"path": "layout/plugin/back_to_top.jsx",
"chars": 785,
"preview": "const { Component, Fragment } = require('inferno');\nconst { cacheComponent } = require('hexo-component-inferno/lib/util/"
},
{
"path": "layout/plugin/pjax.jsx",
"chars": 456,
"preview": "const { Component, Fragment } = require('inferno');\n\nclass Pjax extends Component {\n render() {\n if (this.prop"
},
{
"path": "layout/post.jsx",
"chars": 295,
"preview": "const { Component } = require('inferno');\nconst Article = require('./common/article');\n\nmodule.exports = class extends C"
},
{
"path": "layout/search/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "layout/share/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "layout/tag.jsx",
"chars": 833,
"preview": "const { Component, Fragment } = require('inferno');\nconst Index = require('./index');\n\nmodule.exports = class extends Co"
},
{
"path": "layout/tags.jsx",
"chars": 288,
"preview": "const { Component } = require('inferno');\nconst Tags = require('hexo-component-inferno/lib/view/widget/tags');\n\nmodule.e"
},
{
"path": "layout/widget/profile.jsx",
"chars": 5711,
"preview": "const { Component } = require('inferno');\nconst gravatrHelper = require('hexo-util').gravatar;\nconst { cacheComponent } "
},
{
"path": "package.json",
"chars": 1172,
"preview": "{\n \"name\": \"hexo-theme-icarus\",\n \"version\": \"6.1.1\",\n \"author\": \"ppoffice <ppoffice@users.noreply.github.com>\",\n \"li"
},
{
"path": "scripts/index.js",
"chars": 814,
"preview": "/* global hexo */\nconst createLogger = require('hexo-log');\n\nconst logger = createLogger.default();\n\n/**\n * Print welcom"
},
{
"path": "source/css/cyberpunk.styl",
"chars": 7943,
"preview": "$family-sans-serif ?= 'Oxanium', Ubuntu, Roboto, 'Open Sans', 'Microsoft YaHei', sans-serif\n$family-code ?= 'Roboto Mono"
},
{
"path": "source/css/default.styl",
"chars": 16,
"preview": "@import 'style'\n"
},
{
"path": "source/css/style.styl",
"chars": 635,
"preview": "// Base CSS framework\n@import '../../include/style/base'\n// Helper classes & mixins\n@import '../../include/style/helper'"
},
{
"path": "source/js/.eslintrc.json",
"chars": 132,
"preview": "{\n \"extends\": \"../../.eslintrc.json\",\n \"env\": {\n \"browser\": true,\n \"jquery\": true,\n \"node\": f"
},
{
"path": "source/js/animation.js",
"chars": 2370,
"preview": "(function() {\n function $() {\n return Array.prototype.slice.call(document.querySelectorAll.apply(document, arg"
},
{
"path": "source/js/back_to_top.js",
"chars": 4938,
"preview": "$(document).ready(() => {\n const $button = $('#back-to-top');\n const $footer = $('footer.footer');\n const $main"
},
{
"path": "source/js/column.js",
"chars": 546,
"preview": "(function() {\n function $() {\n return Array.prototype.slice.call(document.querySelectorAll.apply(document, arg"
},
{
"path": "source/js/main.js",
"chars": 6035,
"preview": "/* eslint-disable node/no-unsupported-features/node-builtins */\n(function($, moment, ClipboardJS, config) {\n $('.arti"
},
{
"path": "source/js/pjax.js",
"chars": 1762,
"preview": "(function() {\n // eslint-disable-next-line no-unused-vars\n let pjax;\n\n function initPjax() {\n try {\n "
}
]
About this extraction
This page contains the full source code of the ppoffice/hexo-theme-icarus GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (183.3 KB), approximately 49.3k tokens, and a symbol index with 76 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.