Compare commits
112 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f5fdc3e7fa | ||
|
99790e29f9 | ||
|
1b19bfa135 | ||
|
b6b195941d | ||
|
bf2eaaca73 | ||
|
1649cc8511 | ||
|
7aa7b214b4 | ||
|
f12c76b5cc | ||
|
898e61031f | ||
|
8fefc9f9ad | ||
|
a6e28b073d | ||
|
8a8e70c6c2 | ||
|
16a44fab19 | ||
|
612aaba960 | ||
|
1da900081a | ||
|
26006febba | ||
|
05126a4dc0 | ||
|
4ee3dbff00 | ||
|
6a214c77fc | ||
|
87c0cc79a5 | ||
|
07799bf7b9 | ||
|
ff4e3aa7bb | ||
|
a429df42cc | ||
|
685e92d5af | ||
|
0a7418503d | ||
|
4bae14b796 | ||
|
d938979172 | ||
|
7899d995bc | ||
|
b216b31fe3 | ||
|
30b7e1c088 | ||
|
5fd6f88b37 | ||
|
8a2e3f7080 | ||
|
d94e42c59e | ||
|
612098765c | ||
|
ec1eb4190d | ||
|
119ad99306 | ||
|
51283c41db | ||
|
65cf3b4ff8 | ||
|
1108c55c5c | ||
|
b1bfafce83 | ||
|
895eac4983 | ||
|
3c52a9124f | ||
|
189d5a4449 | ||
|
540c3365dc | ||
|
b90238c26a | ||
|
27a9b3b78d | ||
|
ee860177fc | ||
|
1a57da8cd7 | ||
|
804fedc4b0 | ||
|
beea671c6a | ||
|
1215e56f77 | ||
|
90e9fdc399 | ||
|
5205fceb9d | ||
|
68b44b7b4f | ||
|
e3892044a8 | ||
|
eb50f364e6 | ||
|
832d67476f | ||
|
d524a1b086 | ||
|
558c628821 | ||
|
1d724bba13 | ||
|
217abd30ac | ||
|
ddf1484fc6 | ||
|
984ed3fc04 | ||
|
ad64d75699 | ||
|
0e8b6f10f2 | ||
|
16b53230d6 | ||
|
6688c86662 | ||
|
7665374308 | ||
|
4228274d5b | ||
|
4ff1b60800 | ||
|
523fca45e5 | ||
|
4f5e65302e | ||
|
30d08ec350 | ||
|
98f64814b5 | ||
|
00a4e3f5ba | ||
|
6a4637537b | ||
|
2fce1f82d5 | ||
|
299cabfc74 | ||
|
ddcf1cba63 | ||
|
885ffa3481 | ||
|
6496869ace | ||
|
f3476f38d1 | ||
|
c9f251dae5 | ||
|
4312914114 | ||
|
acb37b3d4d | ||
|
84e9516e64 | ||
|
5efa924d7b | ||
|
8fb8497bff | ||
|
d75005ea6f | ||
|
064bf09264 | ||
|
26178068eb | ||
|
1335240067 | ||
|
6fd83e1ea2 | ||
|
7b4468b379 | ||
|
1e0c6e5ac6 | ||
|
ab9480652b | ||
|
2831b8385f | ||
|
b56f3dede4 | ||
|
ef29a4c25e | ||
|
7a7122125b | ||
|
b18c552f49 | ||
|
cefba8039c | ||
|
872d21fd45 | ||
|
46ac35a4e0 | ||
|
7da15d0014 | ||
|
92e6afb6e5 | ||
|
1b52f8bf8c | ||
|
139094a9c7 | ||
|
b7a3b361b2 | ||
|
671e3e68f4 | ||
|
26727eee29 | ||
|
a0ff8b023b |
@ -51,6 +51,7 @@ module.exports = {
|
||||
|
||||
scopes: [
|
||||
'vuepress-theme-reco',
|
||||
'core',
|
||||
'vuepress-plugin-back-to-top',
|
||||
'vuepress-plugin-comments',
|
||||
'vuepress-plugin-loading',
|
||||
|
@ -2,3 +2,6 @@ styles/
|
||||
images/
|
||||
node_modules/
|
||||
.cz-config.js
|
||||
lib/
|
||||
libs/
|
||||
dist/
|
||||
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: 'https://vuepress-theme-reco.recoluan.com/views/other/donate.html'
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,4 +1,10 @@
|
||||
node_modules
|
||||
yarn-error.log
|
||||
.idea
|
||||
yarn.lock
|
||||
.DS_Store
|
||||
.vscode
|
||||
package-lock.json
|
||||
lib
|
||||
libs
|
||||
dist
|
||||
|
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "packages/vuepress-reco.github.io"]
|
||||
path = packages/vuepress-reco.github.io
|
||||
url = git@github.com:vuepress-reco/vuepress-reco.github.io.git
|
||||
[submodule "packages/theme-cli"]
|
||||
path = packages/theme-cli
|
||||
url = git@github.com:vuepress-reco/theme-cli.git
|
77
CHANGELOG.md
77
CHANGELOG.md
@ -1,3 +1,80 @@
|
||||
## [1.6.6](https://github.com/recoluan/vuepress-theme-reco/compare/v1.6.6-alpha.0...v1.6.6) (2021-03-06)
|
||||
|
||||
|
||||
|
||||
## [1.6.6-alpha.0](https://github.com/recoluan/vuepress-theme-reco/compare/v1.6.5...v1.6.6-alpha.0) (2021-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vuepress-theme-reco:** fix bug of non-ASCII file names cause 404 ([8fefc9f](https://github.com/recoluan/vuepress-theme-reco/commit/8fefc9f9adb82412ef273a8474b7428659f24839)), closes [#276](https://github.com/recoluan/vuepress-theme-reco/issues/276) [#281](https://github.com/recoluan/vuepress-theme-reco/issues/281)
|
||||
* **vuepress-theme-reco:** vuecomponsition-api接口升级方式修改 ([898e610](https://github.com/recoluan/vuepress-theme-reco/commit/898e61031f0516017ee4e1e04d187ecf06591ffc)), closes [#315](https://github.com/recoluan/vuepress-theme-reco/issues/315)
|
||||
* restore the display of the sub sidebar ([8a8e70c](https://github.com/recoluan/vuepress-theme-reco/commit/8a8e70c6c2f7c2fe730559e36fd59f739614b089))
|
||||
|
||||
|
||||
|
||||
## [1.6.5](https://github.com/recoluan/vuepress-theme-reco/compare/v1.6.4...v1.6.5) (2021-02-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vuepress-theme-reco:** fix content display error ([1da9000](https://github.com/recoluan/vuepress-theme-reco/commit/1da900081a78eedb06acaa82f77af677c665b5f9))
|
||||
|
||||
|
||||
|
||||
## [1.6.1](https://github.com/recoluan/vuepress-theme-reco/compare/v1.6.0...v1.6.1) (2020-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix a bug about go back to home page url ([540c336](https://github.com/recoluan/vuepress-theme-reco/commit/540c3365dc0cbe4ee73a20f946b6065e3f7b1227))
|
||||
* fix a bug about siderbar display ([b90238c](https://github.com/recoluan/vuepress-theme-reco/commit/b90238c26a2b39fb8ae824044fab6c7658960f04))
|
||||
* optimize style ([832d674](https://github.com/recoluan/vuepress-theme-reco/commit/832d67476f79c006f30f1c93017f3a08d018c552))
|
||||
* page title ([895eac4](https://github.com/recoluan/vuepress-theme-reco/commit/895eac4983be456f454dcd6f288b07ec51010ffa))
|
||||
* **theme-reco:** fix animation ([1a57da8](https://github.com/recoluan/vuepress-theme-reco/commit/1a57da8cd7a28da19ab372949526245aea8169c3))
|
||||
* **vuepress-plugin-pagation:** fix invalid bug with perPage ([217abd3](https://github.com/recoluan/vuepress-theme-reco/commit/217abd30acea8c33f6f34a893a275bc7a9a8bbb3)), closes [#265](https://github.com/recoluan/vuepress-theme-reco/issues/265)
|
||||
* **vuepress-theme-reco:** fix subSidebar invalid ([6688c86](https://github.com/recoluan/vuepress-theme-reco/commit/6688c866627e3abfb25545f3f7d25a8ecc05e904)), closes [#267](https://github.com/recoluan/vuepress-theme-reco/issues/267)
|
||||
* **vuepress-theme-reco:** solve the problem of className ([16b5323](https://github.com/recoluan/vuepress-theme-reco/commit/16b53230d6c9d3f4ef25b1d9674602aa6ab3f948))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **vuepress-theme-reco:** add social links ([1215e56](https://github.com/recoluan/vuepress-theme-reco/commit/1215e56f77867f441919fe0fc3c55975814d1f93)), closes [#252](https://github.com/recoluan/vuepress-theme-reco/issues/252)
|
||||
* **vuepress-theme-reco:** support time localization ([beea671](https://github.com/recoluan/vuepress-theme-reco/commit/beea671c6a0b9027dbde45dbb4243c0f9d1ca268)), closes [#255](https://github.com/recoluan/vuepress-theme-reco/issues/255)
|
||||
|
||||
|
||||
|
||||
## [1.5.7](https://github.com/recoluan/vuepress-theme-reco/compare/v1.5.5...v1.5.7) (2020-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vuepress-theme-reco:** fix multi-language configuration err ([acb37b3](https://github.com/recoluan/vuepress-theme-reco/commit/acb37b3d4dcaa169f416c5ac3f4d5782865abdc9)), closes [#229](https://github.com/recoluan/vuepress-theme-reco/issues/229)
|
||||
* **vuepress-theme-reco:** fix some style problems ([84e9516](https://github.com/recoluan/vuepress-theme-reco/commit/84e9516e64d2d9d4ed2d9df3e2a28bf64dbd6323)), closes [#231](https://github.com/recoluan/vuepress-theme-reco/issues/231)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **vuepress-plugin-pagation:** set page size by plugin option ([6496869](https://github.com/recoluan/vuepress-theme-reco/commit/6496869ace0ca4571b7ea19a45b77d2764487d5d)), closes [#207](https://github.com/recoluan/vuepress-theme-reco/issues/207)
|
||||
* create plugin notice ([c9f251d](https://github.com/recoluan/vuepress-theme-reco/commit/c9f251dae5f757a6cb8a689f382ba3e9ba438f6f))
|
||||
* **vuepress-theme-reco:** use subSidebar to control the sub sidebar ([5efa924](https://github.com/recoluan/vuepress-theme-reco/commit/5efa924d7bb926223c571ad1393c2ff32aa6ca7b))
|
||||
|
||||
|
||||
|
||||
## [1.5.5](https://github.com/recoluan/vuepress-theme-reco/compare/v1.5.4...v1.5.5) (2020-08-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **vuepress-theme-reco:** optimize blog homepage ([ab94806](https://github.com/recoluan/vuepress-theme-reco/commit/ab9480652bfc8374fcf53df7dabee40641779eeb))
|
||||
* **vuepress-theme-reco:** add locale for 'All' tag label ([7a71221](https://github.com/recoluan/vuepress-theme-reco/commit/7a7122125b897c4316e32d5135f036184e01fa03))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **vuepress-theme-reco:** optimize the home page and subSidebar ([6fd83e1](https://github.com/recoluan/vuepress-theme-reco/commit/6fd83e1ea295ce398c13523739b0900dedfd06d7))
|
||||
|
||||
|
||||
|
||||
## [1.5.4](https://github.com/recoluan/vuepress-theme-reco/compare/v1.5.3...v1.5.4) (2020-07-19)
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
1. This is a Vuepress theme, which is designed to add blog categories, tag walls, pagination, comments and other functions required;
|
||||
2. The theme is minimalist, modified according to the default theme of Vuepress, and the official theme configuration is still applicable;
|
||||
3. Demo:[午后南杂](https://www.recoluan.com)
|
||||
3. Demo:[午后南杂](https://recoluan.com)
|
||||
4. Docs:[vuepress-theme-reco-doc](https://vuepress-theme-reco.recoluan.com)、[github source](https://vuepress.github.io)、[zeit source](https://vuepress-reco-doc.now.sh)
|
||||
|
||||
## Quick start
|
||||
@ -65,6 +65,8 @@ theme-cli init
|
||||
|
||||
**P.S. Thanks to the two beauties for their contributions to the theme logo: Zoey and 冰冰.**
|
||||
|
||||
[Join us](https://www.notion.so/vuepress-reco-f8a7a55d18e042929931b612f170dbf4)
|
||||
|
||||
## License
|
||||
[MIT](https://github.com/recoluan/vuepress-theme-reco/blob/master/LICENSE)
|
||||
|
||||
|
@ -9,7 +9,15 @@ module.exports = {
|
||||
base: '/reco-example-test/',
|
||||
// theme: 'reco',
|
||||
theme: require.resolve('../../packages/vuepress-theme-reco'),
|
||||
locales: {
|
||||
// 键名是该语言所属的子路径
|
||||
// 作为特例,默认语言可以使用 '/' 作为其路径。
|
||||
'/': {
|
||||
lang: 'zh-CN',
|
||||
},
|
||||
},
|
||||
themeConfig: {
|
||||
lastUpdated: false,
|
||||
nav: [
|
||||
{ text: 'Home', link: '/', icon: 'reco-home' },
|
||||
{ text: 'TimeLine', link: '/timeline/', icon: 'reco-date' },
|
||||
@ -45,12 +53,16 @@ module.exports = {
|
||||
blogConfig: {
|
||||
category: {
|
||||
location: 2, // 在导航栏菜单中所占的位置,默认2
|
||||
text: 'Category' // 默认 “分类”
|
||||
// text: 'Categories' // 默认 “分类”
|
||||
},
|
||||
tag: {
|
||||
location: 3, // 在导航栏菜单中所占的位置,默认3
|
||||
text: 'Tag' // 默认 “标签”
|
||||
}
|
||||
// text: 'Tags' // 默认 “标签”
|
||||
},
|
||||
socialLinks: [
|
||||
{ icon: 'reco-github', link: 'https://github.com/recoluan' },
|
||||
{ icon: 'fa-camera', link: 'https://www.npmjs.com/~reco_luan' }
|
||||
]
|
||||
},
|
||||
logo: '/head.png',
|
||||
authorAvatar: '/head.png',
|
||||
@ -58,14 +70,17 @@ module.exports = {
|
||||
search: true,
|
||||
searchMaxSuggestions: 10,
|
||||
// 自动形成侧边导航
|
||||
// sidebar: 'auto',
|
||||
subSidebar: 'auto',
|
||||
sidebarDepth: 4,
|
||||
// 最后更新时间
|
||||
lastUpdated: 'Last Updated',
|
||||
// lastUpdated: 'Last Updated',
|
||||
// 作者
|
||||
author: 'reco_luan',
|
||||
// 备案号
|
||||
record: 'xxxx',
|
||||
recordLink: 'http://www.baidu.com',
|
||||
cyberSecurityRecord: '2222',
|
||||
cyberSecurityLink: 'http://www.baidu.com',
|
||||
// 项目开始时间
|
||||
startYear: '2017',
|
||||
/**
|
||||
@ -96,5 +111,32 @@ module.exports = {
|
||||
* 'tomorrow'
|
||||
* 'twilight'
|
||||
*/
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
['@vuepress-reco/vuepress-plugin-bulletin-popover', {
|
||||
body: [
|
||||
{
|
||||
type: 'title',
|
||||
content: '欢迎加入QQ交流群 🎉🎉🎉',
|
||||
style: 'text-aligin: center;'
|
||||
},
|
||||
{
|
||||
type: 'image',
|
||||
src: '/rvcode_qq.png'
|
||||
}
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
type: 'button',
|
||||
text: '打赏',
|
||||
link: '/donate'
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
text: '打赏',
|
||||
link: '/donate'
|
||||
}
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
|
BIN
example/.vuepress/public/rvcode_qq.png
Normal file
BIN
example/.vuepress/public/rvcode_qq.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
BIN
example/.vuepress/public/rvcode_wx.png
Normal file
BIN
example/.vuepress/public/rvcode_wx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: second page in category1
|
||||
title: second page in category12
|
||||
date: 2019-09-21
|
||||
tags:
|
||||
- tag2
|
||||
|
@ -4,7 +4,7 @@ date: 2018-12-15
|
||||
tags:
|
||||
- tag1
|
||||
categories:
|
||||
- category1
|
||||
- 分类
|
||||
---
|
||||
|
||||
first page in category1
|
@ -1,14 +1,14 @@
|
||||
---
|
||||
title: sidebar test
|
||||
date: 2019-09-21
|
||||
title: sidebar test1111
|
||||
date: '2021/01/24'
|
||||
pageClass: 'customClass customClass2'
|
||||
sidebarDepth: 5
|
||||
tags:
|
||||
- tag2
|
||||
categories:
|
||||
- category1
|
||||
---
|
||||
|
||||
## 二级标题1
|
||||
## 二级标题1 433265344343326534434332653443
|
||||
|
||||
### 三级标题1-1
|
||||
|
||||
|
@ -5,6 +5,7 @@ tags:
|
||||
- webpack
|
||||
categories:
|
||||
- frontEnd
|
||||
publish: false
|
||||
---
|
||||
|
||||
## webpack简介
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: bar1
|
||||
publish: false
|
||||
---
|
||||
|
||||
bar1
|
@ -1,5 +1,3 @@
|
||||
---
|
||||
title: bar1
|
||||
---
|
||||
# bar test
|
||||
|
||||
bar1
|
@ -4,10 +4,14 @@ title: bar2
|
||||
|
||||
bar2
|
||||
|
||||
## sidebar
|
||||
|
||||
## 二级标题1
|
||||
|
||||
### 三级标题1-1
|
||||
|
||||
|
||||
|
||||
#### 四级标题1-1-1
|
||||
#### 四级标题1-1-2
|
||||
#### 四级标题1-1-3
|
||||
|
@ -2,7 +2,7 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "1.5.4",
|
||||
"version": "1.6.6",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
}
|
||||
|
20
package.json
20
package.json
@ -9,16 +9,17 @@
|
||||
],
|
||||
"scripts": {
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"build": "vuepress build example",
|
||||
"build": "concurrently \"npm run build --prefix packages/@vuepress-reco/core\"",
|
||||
"build:example": "vuepress build example",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 2",
|
||||
"commit": "git add . && git-cz",
|
||||
"deploy:example": "bash scripts/deploy.sh",
|
||||
"dev": "vuepress dev example",
|
||||
"eslint-ext": "eslint --ext .js,.vue ./",
|
||||
"eslint-fix": "eslint --fix --ext .js,.vue ./",
|
||||
"prepublish": "lerna publish --dist-tag next",
|
||||
"publish": "lerna publish",
|
||||
"publish": "yarn build && lerna publish",
|
||||
"push": "yarn commit && git push",
|
||||
"test": "bash scripts/test.sh",
|
||||
"update": "yarn upgrade-interactive --latest"
|
||||
},
|
||||
"husky": {
|
||||
@ -45,17 +46,28 @@
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^8.3.5",
|
||||
"@commitlint/config-conventional": "^8.3.4",
|
||||
"@types/events": "^3.0.0",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/unist": "^2.0.3",
|
||||
"@types/vfile": "^4.0.0",
|
||||
"@types/vfile-message": "^2.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.9.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"commitizen": "^4.1.2",
|
||||
"concurrently": "^5.3.0",
|
||||
"conventional-changelog-cli": "^2.0.34",
|
||||
"cz-customizable": "^6.2.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-typescript": "^0.14.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"husky": "^4.2.5",
|
||||
"jest": "^26.6.3",
|
||||
"lerna": "^3.22.0",
|
||||
"lint-staged": "^10.2.7",
|
||||
"sort-package-json": "^1.44.0",
|
||||
"vuepress": "^1.5.0"
|
||||
"ts-jest": "^26.4.4",
|
||||
"typescript": "4.1.2",
|
||||
"vuepress": "^1.8.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
4
packages/@vuepress-reco/core/.npmignore
Normal file
4
packages/@vuepress-reco/core/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
__tests__
|
||||
__mocks__
|
||||
node_modules
|
||||
src
|
11
packages/@vuepress-reco/core/README.md
Normal file
11
packages/@vuepress-reco/core/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# `core`
|
||||
|
||||
> TODO: description
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
const core = require('core');
|
||||
|
||||
// TODO: DEMONSTRATE API
|
||||
```
|
36
packages/@vuepress-reco/core/package.json
Normal file
36
packages/@vuepress-reco/core/package.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@vuepress-reco/core",
|
||||
"version": "1.6.2",
|
||||
"description": "The core library of vuepress-theme-reco.",
|
||||
"homepage": "https://vuepress-theme-reco.recoluan.com/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/recoluan/vuepress-theme-reco/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/recoluan/vuepress-theme-reco.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
"main": "lib/index.js",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "^1.0.0-beta.20",
|
||||
"vue": "^2.6.12",
|
||||
"vue-demi": "^0.5.3",
|
||||
"vue-property-decorator": "^9.1.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import Vue from 'vue';
|
||||
import Component from 'vue-class-component';
|
||||
|
||||
const ModuleTransitionProps = Vue.extend({
|
||||
props: {
|
||||
delay: {
|
||||
type: String,
|
||||
default: '0'
|
||||
},
|
||||
duration: {
|
||||
type: String,
|
||||
default: '.25'
|
||||
},
|
||||
transform: {
|
||||
type: Array,
|
||||
default () {
|
||||
return ['translateY(-20px)', 'translateY(0)']
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@Component
|
||||
class ModuleTransition extends ModuleTransitionProps {
|
||||
setStyle (items) {
|
||||
items.style.transition = `transform ${this.duration}s ease-in-out ${this.delay}s, opacity ${this.duration}s ease-in-out ${this.delay}s`
|
||||
items.style.transform = this.transform[0]
|
||||
items.style.opacity = 0
|
||||
}
|
||||
|
||||
unsetStyle (items) {
|
||||
items.style.transform = this.transform[1]
|
||||
items.style.opacity = 1
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<transition
|
||||
{
|
||||
...{
|
||||
attrs: { name: 'module' },
|
||||
on: {
|
||||
enter: this.setStyle,
|
||||
appear: this.setStyle,
|
||||
'before-leave': this.setStyle,
|
||||
'after-appear': this.unsetStyle,
|
||||
'after-enter': this.unsetStyle
|
||||
}
|
||||
}
|
||||
}
|
||||
>{this.$slots.default}</transition>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ModuleTransition
|
47
packages/@vuepress-reco/core/src/components/RecoIcon.tsx
Normal file
47
packages/@vuepress-reco/core/src/components/RecoIcon.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import Vue from 'vue'
|
||||
import Component from 'vue-class-component'
|
||||
|
||||
const ICON_REGEXP = /^(\w+)\-/
|
||||
|
||||
const RecoIconProps = Vue.extend({
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
link: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@Component
|
||||
class RecoIcon extends RecoIconProps {
|
||||
getClass (icon: string) {
|
||||
if (ICON_REGEXP.test(icon)) {
|
||||
return icon.replace(ICON_REGEXP, (...args) => {
|
||||
return args[1] === 'reco' ? `iconfont ${args[0]}` : `${args[1]} ${args[0]}`
|
||||
})
|
||||
}
|
||||
return icon
|
||||
}
|
||||
|
||||
go (link) {
|
||||
if (link === '') return
|
||||
window.open(link)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<i {...{
|
||||
class: this.getClass(this.icon),
|
||||
on: { click: this.go.bind(this, this.link) }
|
||||
}}>
|
||||
{this.$slots.default}
|
||||
</i>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default RecoIcon
|
3
packages/@vuepress-reco/core/src/components/index.ts
Normal file
3
packages/@vuepress-reco/core/src/components/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import RecoIcon from './RecoIcon'
|
||||
import ModuleTransition from './ModuleTransition'
|
||||
export { RecoIcon, ModuleTransition }
|
2
packages/@vuepress-reco/core/src/index.ts
Normal file
2
packages/@vuepress-reco/core/src/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './utils'
|
||||
export * from './components'
|
7
packages/@vuepress-reco/core/src/utils/index.ts
Normal file
7
packages/@vuepress-reco/core/src/utils/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export function isArray (target: any): boolean {
|
||||
return Array.isArray(target)
|
||||
}
|
||||
|
||||
export function isString (target: any): boolean {
|
||||
return typeof target === 'string'
|
||||
}
|
11
packages/@vuepress-reco/core/tsconfig.json
Normal file
11
packages/@vuepress-reco/core/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": [
|
||||
"./src"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"jsx": "react-native",
|
||||
"outDir": "./lib",
|
||||
"noImplicitAny": false
|
||||
}
|
||||
}
|
@ -18,10 +18,10 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
window.addEventListener('scroll', this.throttle(this.handleScroll, 500))
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('scroll', this.handleScroll)
|
||||
window.removeEventListener('scroll', this.throttle(this.handleScroll, 500))
|
||||
},
|
||||
methods: {
|
||||
handleScroll () {
|
||||
@ -29,6 +29,25 @@ export default {
|
||||
},
|
||||
backToTop () {
|
||||
window.scrollTo(0, 0)
|
||||
},
|
||||
throttle (func, delay) {
|
||||
let timer = null
|
||||
let startTime = Date.now()
|
||||
|
||||
return function () {
|
||||
const curTime = Date.now()
|
||||
const remaining = delay - (curTime - startTime)
|
||||
const context = this
|
||||
const args = arguments
|
||||
|
||||
clearTimeout(timer)
|
||||
if (remaining <= 0) {
|
||||
func.apply(context, args)
|
||||
startTime = Date.now()
|
||||
} else {
|
||||
timer = setTimeout(func, remaining)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vuepress-reco/vuepress-plugin-back-to-top",
|
||||
"version": "1.5.4",
|
||||
"version": "1.6.0",
|
||||
"description": "Back-to-top plugin for vuepress-theme-reco or other vuepress theme",
|
||||
"keywords": [
|
||||
"vuepress-theme-reco",
|
||||
@ -9,7 +9,7 @@
|
||||
],
|
||||
"homepage": "https://vuepress-theme-reco.recoluan.com",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vuepress-reco/vuepress-plugin-pagation/issues"
|
||||
"url": "https://github.com/vuepress-reco/vuepress-theme-reco/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -17,5 +17,8 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
"main": "index.js"
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
__tests__
|
||||
__mocks__
|
||||
node_modules
|
@ -0,0 +1,87 @@
|
||||
# @vuepress-reco/vuepress-plugin-bulletin-popover
|
||||
|
||||
## Introduce
|
||||
|
||||
Bulletin popover plugin for vuepress-theme-reco or other vuepress theme.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
plugins: [
|
||||
['@vuepress-reco/vuepress-plugin-bulletin-popover', {
|
||||
title: '消息提示',
|
||||
body: [
|
||||
{
|
||||
type: 'title',
|
||||
content: '欢迎加入QQ交流群 🎉🎉🎉',
|
||||
style: 'text-aligin: center;'
|
||||
},
|
||||
{
|
||||
type: 'image',
|
||||
src: '/rvcode_qq.png'
|
||||
}
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
type: 'button',
|
||||
text: '打赏',
|
||||
link: '/donate'
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
text: '打赏',
|
||||
link: '/donate'
|
||||
}
|
||||
]
|
||||
}]
|
||||
]
|
||||
```
|
||||
|
||||
弹窗分为三部分,公告标题、公告内容和公告底部操作。其中标题是普通文本,公告内容和公告底部操作内容均为数组,支持 4 种 dom,需要通过 schema 配置来控制显示效果,可以根据需要自由组合:
|
||||
|
||||
**标题**
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'title',
|
||||
content: '这里显示 h5 标题'
|
||||
}
|
||||
```
|
||||
|
||||
**文本**
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'text',
|
||||
content: '这里显示普通文本'
|
||||
}
|
||||
```
|
||||
|
||||
**图片**
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'image',
|
||||
src: '/rvcode_qq.png'
|
||||
}
|
||||
```
|
||||
|
||||
**按钮**
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'button',
|
||||
text: '打赏',
|
||||
link: '/donate'
|
||||
}
|
||||
```
|
||||
|
||||
**给 dom 添加样式**
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'title',
|
||||
content: '这里显示 h5 标题',
|
||||
style: 'text-aligin: center;'
|
||||
}
|
||||
```
|
@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div v-if="visible" class="bulletin-wrapper" :style="{ width }">
|
||||
<h4 class="bulletin-title">
|
||||
<reco-icon icon="reco-tongzhi" />
|
||||
<span>{{ title || bulletinLocales.title }}</span>
|
||||
<i class="btn-close" @click="closeNote">
|
||||
<svg t="1573745677073" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4448" width="22" height="22"><path d="M512 34.133333a486.4 486.4 0 1 0 486.4 486.4A486.4 486.4 0 0 0 512 34.133333z m209.4848 632.8064l-55.6032 55.466667-151.517867-151.125333-151.517866 151.1168-55.6032-55.466667 151.517866-151.108267L307.242667 364.714667l55.6032-55.466667 151.517866 151.125333 151.517867-151.1168 55.6032 55.466667-151.517867 151.099733z m0 0" p-id="4449"></path></svg>
|
||||
</i>
|
||||
</h4>
|
||||
<div class="bulletin-content" v-html="bodyNodes"></div>
|
||||
<hr>
|
||||
<div class="bulletin-footer" v-html="footerNodes"></div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import bulletinLocales from './locales'
|
||||
|
||||
export default {
|
||||
components: { RecoIcon },
|
||||
name: 'Bulletin',
|
||||
data () {
|
||||
return {
|
||||
visible: false,
|
||||
/* eslint-disable no-undef */
|
||||
title: TITLE,
|
||||
width: WIDTH,
|
||||
body: BODY,
|
||||
footer: FOOTER
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
bodyNodes () {
|
||||
return this.handleNode(this.body).join('')
|
||||
},
|
||||
footerNodes () {
|
||||
return this.handleNode(this.footer).join('')
|
||||
},
|
||||
bulletinLocales () {
|
||||
return bulletinLocales(this)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const closeNote = sessionStorage.getItem('closeNote')
|
||||
this.visible = closeNote !== 'true'
|
||||
},
|
||||
methods: {
|
||||
closeNote () {
|
||||
this.visible = false
|
||||
sessionStorage.setItem('closeNote', 'true')
|
||||
},
|
||||
handleNode (nodes) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
let type = nodes.type
|
||||
type = type.slice(0, 1).toUpperCase() + type.slice(1)
|
||||
return this[`handle${type}`](nodes)
|
||||
} else {
|
||||
return nodes.map(node => this.handleNode(node))
|
||||
}
|
||||
},
|
||||
handleImage (node) {
|
||||
return `<img style=\"${node.style || ''}\" src=\"${node.src}\" />`
|
||||
},
|
||||
handleText (node) {
|
||||
return `<p style=\"${node.style || ''}\">${node.content}</p>`
|
||||
},
|
||||
handleTitle (node) {
|
||||
return `<h5 style=\"${node.style || ''}\">${node.content}</h5>`
|
||||
},
|
||||
handleButton (node) {
|
||||
return `<a style=\"${node.style || ''}\" class=\"btn\" href=\"${node.link}\">${node.text}</a>`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.bulletin-wrapper
|
||||
position fixed
|
||||
top 80px
|
||||
right 20px
|
||||
z-index 19
|
||||
box-sizing border-box
|
||||
background #fff
|
||||
border 1px solid $accentColor
|
||||
border-radius .25rem
|
||||
background var(--background-color)
|
||||
box-shadow var(--box-shadow)
|
||||
.bulletin-title
|
||||
position relative
|
||||
box-sizing border-box
|
||||
padding 10px
|
||||
margin 0
|
||||
background $accentColor
|
||||
color #fff
|
||||
i
|
||||
color #fff
|
||||
.btn-close
|
||||
position absolute
|
||||
display inline-block
|
||||
width 22px
|
||||
height 22px
|
||||
right 10px
|
||||
top 0
|
||||
bottom 0
|
||||
margin auto
|
||||
cursor pointer
|
||||
svg
|
||||
fill #fff
|
||||
.bulletin-content
|
||||
box-sizing border-box
|
||||
padding 10px 15px 0
|
||||
::v-deep h5
|
||||
margin .2rem 0
|
||||
text-align center
|
||||
::v-deep img
|
||||
width 100%
|
||||
.bulletin-footer
|
||||
padding 16px
|
||||
text-align center
|
||||
::v-deep .btn
|
||||
display inline-block
|
||||
width 3.4rem
|
||||
line-height 3.4rem
|
||||
text-align center
|
||||
background-color $accentColor
|
||||
border-radius 50%
|
||||
color #fff
|
||||
font-size 1rem
|
||||
box-shadow var(--box-shadow)
|
||||
cursor pointer
|
||||
&:not(:first-child)
|
||||
margin-left 10px
|
||||
::v-deep h5
|
||||
margin .2rem 0
|
||||
text-align center
|
||||
::v-deep img
|
||||
width 100%
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,5 @@
|
||||
import Bulletin from './Bulletin.vue'
|
||||
|
||||
export default ({ Vue }) => {
|
||||
Vue.component('Bulletin', Bulletin)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
const zhHans = {
|
||||
title: '公告'
|
||||
}
|
||||
|
||||
const zhHant = {
|
||||
title: '公告'
|
||||
}
|
||||
|
||||
const en = {
|
||||
title: 'Bulletin'
|
||||
}
|
||||
|
||||
const ja = {
|
||||
bulletin: '公告'
|
||||
}
|
||||
|
||||
const ko = {
|
||||
title: '공고'
|
||||
}
|
||||
|
||||
export default function bulletinLocales (ctx) {
|
||||
const { $lang, $recoLocales: { pagation } = {} } = ctx
|
||||
if (pagation) {
|
||||
return pagation
|
||||
}
|
||||
if (/^zh\-(CN|SG)$/.test($lang)) {
|
||||
return zhHans
|
||||
}
|
||||
if (/^zh\-(HK|MO|TW)$/.test($lang)) {
|
||||
return zhHant
|
||||
}
|
||||
if (/^ja\-JP$/.test($lang)) {
|
||||
return ja
|
||||
}
|
||||
if (/^ko\-KR$/.test($lang)) {
|
||||
return ko
|
||||
}
|
||||
return en
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
const { path } = require('@vuepress/shared-utils')
|
||||
|
||||
module.exports = (options, context) => ({
|
||||
define () {
|
||||
const { title, width, body, footer } = options || {}
|
||||
return {
|
||||
WIDTH: width || '260px',
|
||||
TITLE: title || '公告',
|
||||
BODY: body || [],
|
||||
FOOTER: footer || []
|
||||
}
|
||||
},
|
||||
name: '@vuepress-reco/vuepress-plugin-bulletin-popover',
|
||||
enhanceAppFiles: [
|
||||
path.resolve(__dirname, './bin/enhanceAppFile.js')
|
||||
],
|
||||
globalUIComponents: 'Bulletin'
|
||||
})
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@vuepress-reco/vuepress-plugin-bulletin-popover",
|
||||
"version": "1.6.0",
|
||||
"description": "Bulletin popover plugin for vuepress-theme-reco or other vuepress theme",
|
||||
"keywords": [
|
||||
"vuepress-theme-reco",
|
||||
"bulletin",
|
||||
"vuepress"
|
||||
],
|
||||
"homepage": "https://vuepress-theme-reco.recoluan.com",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vuepress-reco/vuepress-theme-reco/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-plugin-bulletin-popover.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vuepress-reco/vuepress-plugin-comments",
|
||||
"version": "1.4.6",
|
||||
"version": "1.6.0",
|
||||
"description": "Comments plugin for vuepress-theme-reco or other vuepress theme",
|
||||
"keywords": [
|
||||
"vuepress-theme-reco",
|
||||
@ -13,7 +13,7 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-theme-reco.git"
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-plugin-comments.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
@ -26,5 +26,8 @@
|
||||
"@vssue/api-gitlab-v4": "^1.1.1",
|
||||
"valine": "^1.4.14",
|
||||
"vssue": "^1.4.6"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vuepress-reco/vuepress-plugin-loading-page",
|
||||
"version": "1.4.0",
|
||||
"version": "1.6.0",
|
||||
"description": "Loading page plugin for vuepress-theme-reco or other vuepress theme",
|
||||
"keywords": [
|
||||
"vuepress-theme-reco",
|
||||
@ -13,10 +13,13 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-theme-reco.git"
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-plugin-loading-page.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "c3a1db8487bece9341b6269a0f6ebf910cd5462a"
|
||||
}
|
||||
|
@ -76,7 +76,9 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
changePage: '' // 跳转页
|
||||
changePage: '', // 跳转页
|
||||
/* eslint-disable no-undef */
|
||||
pageSize: PERPAGE
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -86,7 +88,7 @@ export default {
|
||||
},
|
||||
perPage: {
|
||||
type: Number,
|
||||
default: 2
|
||||
default: 10
|
||||
},
|
||||
currentPage: {
|
||||
type: Number,
|
||||
@ -95,7 +97,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
pages () {
|
||||
return Math.ceil(this.total / this.perPage)
|
||||
const pageSize = this.pageSize || this.perPage
|
||||
return Math.ceil(this.total / pageSize)
|
||||
},
|
||||
show: function () {
|
||||
return this.pages && this.pages != 1
|
||||
|
@ -47,7 +47,9 @@ import pagationLocales from './locales'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
changePage: '' // 跳转页
|
||||
changePage: '', // 跳转页
|
||||
/* eslint-disable no-undef */
|
||||
pageSize: PERPAGE
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -66,7 +68,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
pages () {
|
||||
return Math.ceil(this.total / this.perPage)
|
||||
const pageSize = this.pageSize || this.perPage
|
||||
return Math.ceil(this.total / pageSize)
|
||||
},
|
||||
show: function () {
|
||||
return this.pages && this.pages != 1
|
||||
|
@ -1,8 +1,26 @@
|
||||
const { path } = require('@vuepress/shared-utils')
|
||||
|
||||
module.exports = (options, context) => ({
|
||||
name: '@vuepress-reco/vuepress-plugin-pagation',
|
||||
enhanceAppFiles: [
|
||||
path.resolve(__dirname, './bin/enhanceAppFile.js')
|
||||
]
|
||||
})
|
||||
module.exports = (options, context) => {
|
||||
const { perPage = 10 } = options || {}
|
||||
return {
|
||||
define () {
|
||||
return {
|
||||
PERPAGE: perPage
|
||||
}
|
||||
},
|
||||
name: '@vuepress-reco/vuepress-plugin-pagation',
|
||||
enhanceAppFiles: [
|
||||
path.resolve(__dirname, './bin/enhanceAppFile.js'),
|
||||
() => ({
|
||||
name: 'dynamic-pagation',
|
||||
content: `export default ({ Vue }) => {
|
||||
Vue.mixin({
|
||||
computed: {
|
||||
$perPage () { return ${perPage} }
|
||||
}
|
||||
})
|
||||
}`
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vuepress-reco/vuepress-plugin-pagation",
|
||||
"version": "1.4.7",
|
||||
"version": "1.6.0",
|
||||
"description": "Pagation plugin for vuepress-theme-reco or other vuepress theme",
|
||||
"keywords": [
|
||||
"vuepress-theme-reco",
|
||||
@ -13,9 +13,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-theme-reco.git"
|
||||
"url": "git+https://github.com/vuepress-reco/vuepress-plugin-pagation.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "reco_luan <recoluan@outlook.com>",
|
||||
"main": "index.js"
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
1
packages/theme-cli
Submodule
1
packages/theme-cli
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 03ccebd77846c71c5e5e3432fb7697f0bc06520b
|
1
packages/vuepress-reco.github.io
Submodule
1
packages/vuepress-reco.github.io
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 0f641fc3704927ec438a41782b29a4152fb1d9bb
|
@ -4,7 +4,7 @@
|
||||
class="algolia-search-wrapper search-box"
|
||||
role="search"
|
||||
>
|
||||
<i class="iconfont reco-search"></i>
|
||||
<reco-icon icon="reco-search" />
|
||||
<input
|
||||
id="algolia-search-input"
|
||||
class="search-query"
|
||||
@ -14,20 +14,20 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['options'],
|
||||
data () {
|
||||
return {
|
||||
placeholder: undefined
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initialize(this.options, this.$lang)
|
||||
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
|
||||
},
|
||||
import { defineComponent, ref, onMounted, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
methods: {
|
||||
initialize (userOptions, lang) {
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
|
||||
props: ['options'],
|
||||
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const placeholder = ref(undefined)
|
||||
|
||||
const initialize = (userOptions, lang) => {
|
||||
Promise.all([
|
||||
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
|
||||
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
|
||||
@ -50,12 +50,19 @@ export default {
|
||||
}
|
||||
))
|
||||
})
|
||||
},
|
||||
|
||||
update (options, lang) {
|
||||
this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
|
||||
this.initialize(options, lang)
|
||||
}
|
||||
|
||||
const update = (options, lang) => {
|
||||
instance.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
|
||||
instance.initialize(options, lang)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initialize(props.options, instance.$lang)
|
||||
placeholder.value = instance.$site.themeConfig.searchPlaceholder || ''
|
||||
})
|
||||
|
||||
return { placeholder, initialize, update }
|
||||
},
|
||||
|
||||
watch: {
|
||||
@ -67,11 +74,10 @@ export default {
|
||||
this.update(newValue, this.$lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/mode.styl'
|
||||
.algolia-search-wrapper
|
||||
& > span
|
||||
vertical-align middle
|
||||
|
@ -1,34 +1,22 @@
|
||||
<template>
|
||||
<div
|
||||
class="theme-container"
|
||||
:class="pageClasses"
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd">
|
||||
<div class="theme-container" :class="pageClasses">
|
||||
<div v-if="!absoluteEncryption">
|
||||
<transition name="fade">
|
||||
<LoadingPage v-show="firstLoad" class="loading-wrapper" />
|
||||
</transition>
|
||||
|
||||
<transition name="fade">
|
||||
<Password v-show="!isHasKey" class="password-wrapper-out" key="out" />
|
||||
<Password v-show="!firstLoad && !isHasKey" class="password-wrapper-out" key="out" />
|
||||
</transition>
|
||||
|
||||
<div :class="{ 'hide': firstLoad || !isHasKey }">
|
||||
<Navbar
|
||||
v-if="shouldShowNavbar"
|
||||
@toggle-sidebar="toggleSidebar"/>
|
||||
<Navbar v-if="shouldShowNavbar" @toggle-sidebar="toggleSidebar" />
|
||||
|
||||
<div
|
||||
class="sidebar-mask"
|
||||
@click="toggleSidebar(false)"></div>
|
||||
<div class="sidebar-mask" @click="toggleSidebar(false)"></div>
|
||||
|
||||
<Sidebar
|
||||
:items="sidebarItems"
|
||||
@toggle-sidebar="toggleSidebar">
|
||||
<template slot="top">
|
||||
<PersonalInfo />
|
||||
</template>
|
||||
<slot
|
||||
name="sidebar-bottom"
|
||||
slot="bottom"/>
|
||||
<Sidebar :items="sidebarItems" @toggle-sidebar="toggleSidebar">
|
||||
<PersonalInfo slot="top" />
|
||||
<slot name="sidebar-bottom" slot="bottom"/>
|
||||
</Sidebar>
|
||||
|
||||
<Password v-show="!isHasPageKey" :isPage="true" class="password-wrapper-in" key="in"></Password>
|
||||
@ -42,29 +30,17 @@
|
||||
<LoadingPage v-if="firstLoad" />
|
||||
<Password v-else-if="!isHasKey" />
|
||||
<div v-else>
|
||||
<Navbar
|
||||
v-if="shouldShowNavbar"
|
||||
@toggle-sidebar="toggleSidebar"/>
|
||||
<Navbar v-if="shouldShowNavbar" @toggle-sidebar="toggleSidebar"/>
|
||||
|
||||
<div
|
||||
class="sidebar-mask"
|
||||
@click="toggleSidebar(false)"></div>
|
||||
<div class="sidebar-mask" @click="toggleSidebar(false)"></div>
|
||||
|
||||
<Sidebar
|
||||
:items="sidebarItems"
|
||||
@toggle-sidebar="toggleSidebar">
|
||||
<template slot="top">
|
||||
<PersonalInfo />
|
||||
</template>
|
||||
<slot
|
||||
name="sidebar-bottom"
|
||||
slot="bottom"/>
|
||||
<Sidebar :items="sidebarItems" @toggle-sidebar="toggleSidebar">
|
||||
<PersonalInfo slot="top" />
|
||||
<slot name="sidebar-bottom" slot="bottom"/>
|
||||
</Sidebar>
|
||||
|
||||
<Password v-if="!isHasPageKey" :isPage="true"></Password>
|
||||
<div v-else>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<slot v-else></slot>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
@ -72,16 +48,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, ref, onMounted, toRefs, getCurrentInstance } from 'vue-demi'
|
||||
import Navbar from '@theme/components/Navbar'
|
||||
import Sidebar from '@theme/components/Sidebar'
|
||||
import PersonalInfo from '@theme/components/PersonalInfo'
|
||||
import Password from '@theme/components/Password'
|
||||
import { setTimeout } from 'timers'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [moduleTransitonMixin],
|
||||
|
||||
export default defineComponent({
|
||||
components: { Sidebar, Navbar, Password, PersonalInfo },
|
||||
|
||||
props: {
|
||||
@ -92,26 +66,28 @@ export default {
|
||||
sidebarItems: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
isSidebarOpen: false,
|
||||
isHasKey: true,
|
||||
isHasPageKey: true,
|
||||
firstLoad: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
absoluteEncryption () {
|
||||
return this.$themeConfig.keyPage && this.$themeConfig.keyPage.absoluteEncryption === true
|
||||
},
|
||||
showModule: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
shouldShowNavbar () {
|
||||
const { themeConfig } = this.$site
|
||||
const { frontmatter } = this.$page
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const isSidebarOpen = ref(false)
|
||||
const isHasKey = ref(true)
|
||||
const isHasPageKey = ref(true)
|
||||
const firstLoad = ref(true)
|
||||
|
||||
const shouldShowSidebar = computed(() => props.sidebarItems.length > 0)
|
||||
const absoluteEncryption = computed(() => {
|
||||
return instance.$themeConfig.keyPage && instance.$themeConfig.keyPage.absoluteEncryption === true
|
||||
})
|
||||
const shouldShowNavbar = computed(() => {
|
||||
const { themeConfig } = instance.$site
|
||||
const { frontmatter } = instance.$page
|
||||
|
||||
if (
|
||||
frontmatter.navbar === false ||
|
||||
@ -119,102 +95,83 @@ export default {
|
||||
) return false
|
||||
|
||||
return (
|
||||
this.$title ||
|
||||
instance.$title ||
|
||||
themeConfig.logo ||
|
||||
themeConfig.repo ||
|
||||
themeConfig.nav ||
|
||||
this.$themeLocaleConfig.nav
|
||||
instance.$themeLocaleConfig.nav
|
||||
)
|
||||
},
|
||||
|
||||
shouldShowSidebar () {
|
||||
// const { frontmatter } = this.$page
|
||||
// return (
|
||||
// this.sidebar !== false &&
|
||||
// !frontmatter.home &&
|
||||
// frontmatter.sidebar !== false &&
|
||||
// this.sidebarItems.length
|
||||
// )
|
||||
return this.sidebarItems.length > 0
|
||||
},
|
||||
|
||||
pageClasses () {
|
||||
const userPageClass = this.$frontmatter.pageClass
|
||||
return [
|
||||
{
|
||||
'no-navbar': !this.shouldShowNavbar,
|
||||
'sidebar-open': this.isSidebarOpen,
|
||||
'no-sidebar': !this.shouldShowSidebar
|
||||
},
|
||||
userPageClass
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$router.afterEach(() => {
|
||||
this.isSidebarOpen = false
|
||||
})
|
||||
|
||||
this.hasKey()
|
||||
this.hasPageKey()
|
||||
this.handleLoading()
|
||||
},
|
||||
const pageClasses = computed(() => {
|
||||
const classValue = {
|
||||
'no-navbar': !shouldShowNavbar.value,
|
||||
'sidebar-open': isSidebarOpen.value,
|
||||
'no-sidebar': !shouldShowSidebar.value
|
||||
}
|
||||
|
||||
methods: {
|
||||
hasKey () {
|
||||
const keyPage = this.$themeConfig.keyPage
|
||||
const { pageClass: userPageClass } = instance.$frontmatter || {}
|
||||
if (userPageClass) classValue[userPageClass] = true
|
||||
|
||||
return classValue
|
||||
})
|
||||
|
||||
const hasKey = () => {
|
||||
const { keyPage } = instance.$themeConfig
|
||||
if (!keyPage || !keyPage.keys || keyPage.keys.length === 0) {
|
||||
this.isHasKey = true
|
||||
isHasKey.value = true
|
||||
return
|
||||
}
|
||||
|
||||
let { keys } = keyPage
|
||||
keys = keys.map(item => item.toLowerCase())
|
||||
this.isHasKey = keys && keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
},
|
||||
hasPageKey () {
|
||||
let pageKeys = this.$frontmatter.keys
|
||||
isHasKey.value = keys && keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
}
|
||||
const initRouterHandler = () => {
|
||||
instance.$router.afterEach(() => {
|
||||
isSidebarOpen.value = false
|
||||
})
|
||||
}
|
||||
const hasPageKey = () => {
|
||||
let pageKeys = instance.$frontmatter.keys
|
||||
if (!pageKeys || pageKeys.length === 0) {
|
||||
this.isHasPageKey = true
|
||||
isHasPageKey.value = true
|
||||
return
|
||||
}
|
||||
|
||||
pageKeys = pageKeys.map(item => item.toLowerCase())
|
||||
|
||||
this.isHasPageKey = pageKeys.indexOf(sessionStorage.getItem(`pageKey${window.location.pathname}`)) > -1
|
||||
},
|
||||
toggleSidebar (to) {
|
||||
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
|
||||
},
|
||||
|
||||
// side swipe
|
||||
onTouchStart (e) {
|
||||
this.touchStart = {
|
||||
x: e.changedTouches[0].clientX,
|
||||
y: e.changedTouches[0].clientY
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd (e) {
|
||||
const dx = e.changedTouches[0].clientX - this.touchStart.x
|
||||
const dy = e.changedTouches[0].clientY - this.touchStart.y
|
||||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||||
if (dx > 0 && this.touchStart.x <= 80) {
|
||||
this.toggleSidebar(true)
|
||||
} else {
|
||||
this.toggleSidebar(false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleLoading () {
|
||||
const time = this.$frontmatter.home && sessionStorage.getItem('firstLoad') == undefined ? 1000 : 0
|
||||
isHasPageKey.value = pageKeys.indexOf(sessionStorage.getItem(`pageKey${window.location.pathname}`)) > -1
|
||||
}
|
||||
const toggleSidebar = (to) => {
|
||||
isSidebarOpen.value = typeof to === 'boolean' ? to : !isSidebarOpen.value
|
||||
}
|
||||
const handleLoading = () => {
|
||||
const time = instance.$frontmatter.home && sessionStorage.getItem('firstLoad') == undefined ? 1000 : 0
|
||||
setTimeout(() => {
|
||||
this.firstLoad = false
|
||||
firstLoad.value = false
|
||||
if (sessionStorage.getItem('firstLoad') == undefined) sessionStorage.setItem('firstLoad', false)
|
||||
}, time)
|
||||
}
|
||||
|
||||
// 首次渲染时,recoShowModule 直接为 true,否则锚点失效
|
||||
const { showModule } = toRefs(props)
|
||||
const recoShowModule = computed(() => {
|
||||
if (firstLoad.value) {
|
||||
return true
|
||||
} else {
|
||||
return showModule.value
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initRouterHandler()
|
||||
hasKey()
|
||||
hasPageKey()
|
||||
handleLoading()
|
||||
})
|
||||
|
||||
return { isSidebarOpen, absoluteEncryption, shouldShowNavbar, shouldShowSidebar, pageClasses, hasKey, hasPageKey, isHasKey, isHasPageKey, toggleSidebar, firstLoad, recoShowModule }
|
||||
},
|
||||
|
||||
watch: {
|
||||
@ -223,7 +180,7 @@ export default {
|
||||
this.hasPageKey()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@ -254,9 +211,10 @@ export default {
|
||||
.hide
|
||||
height 100vh
|
||||
overflow hidden
|
||||
opacity 0
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
transition: opacity .5s ease-in-out .5s;
|
||||
}
|
||||
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
|
@ -1,27 +1,15 @@
|
||||
<template>
|
||||
<div
|
||||
class="dropdown-wrapper"
|
||||
:class="{ open }"
|
||||
>
|
||||
<a
|
||||
class="dropdown-title"
|
||||
@click="toggle"
|
||||
>
|
||||
<div class="dropdown-wrapper" :class="{ open }">
|
||||
<a class="dropdown-title" @click="toggle">
|
||||
<span class="title">
|
||||
<i :class="`iconfont ${item.icon}`"></i>
|
||||
<reco-icon :icon="`${item.icon}`" />
|
||||
{{ item.text }}
|
||||
</span>
|
||||
<span
|
||||
class="arrow"
|
||||
:class="open ? 'down' : 'right'"
|
||||
></span>
|
||||
<span class="arrow" :class="open ? 'down' : 'right'"></span>
|
||||
</a>
|
||||
|
||||
<DropdownTransition>
|
||||
<ul
|
||||
class="nav-dropdown"
|
||||
v-show="open"
|
||||
>
|
||||
<ul class="nav-dropdown" v-show="open">
|
||||
<li
|
||||
class="dropdown-item"
|
||||
:key="subItem.link || index"
|
||||
@ -37,15 +25,10 @@
|
||||
class="dropdown-subitem"
|
||||
:key="childSubItem.link"
|
||||
v-for="childSubItem in subItem.items"
|
||||
>
|
||||
<NavLink :item="childSubItem"/>
|
||||
</li>
|
||||
><NavLink :item="childSubItem"/></li>
|
||||
</ul>
|
||||
|
||||
<NavLink
|
||||
v-else
|
||||
:item="subItem"
|
||||
/>
|
||||
<NavLink v-else :item="subItem" />
|
||||
</li>
|
||||
</ul>
|
||||
</DropdownTransition>
|
||||
@ -53,17 +36,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import NavLink from '@theme/components/NavLink'
|
||||
import DropdownTransition from '@theme/components/DropdownTransition'
|
||||
|
||||
export default {
|
||||
components: { NavLink, DropdownTransition },
|
||||
|
||||
data () {
|
||||
return {
|
||||
open: false
|
||||
}
|
||||
},
|
||||
export default defineComponent({
|
||||
components: { NavLink, DropdownTransition, RecoIcon },
|
||||
|
||||
props: {
|
||||
item: {
|
||||
@ -71,17 +50,19 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggle () {
|
||||
this.open = !this.open
|
||||
setup (props, ctx) {
|
||||
const open = ref(false)
|
||||
|
||||
const toggle = () => {
|
||||
open.value = !open.value
|
||||
}
|
||||
|
||||
return { open, toggle }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.dropdown-wrapper
|
||||
cursor pointer
|
||||
.dropdown-title
|
||||
|
@ -10,20 +10,22 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import { defineComponent } from 'vue-demi'
|
||||
export default defineComponent({
|
||||
name: 'DropdownTransition',
|
||||
|
||||
methods: {
|
||||
setHeight (items) {
|
||||
// explicitly set height so that it can be transitioned
|
||||
setup (props, ctx) {
|
||||
const setHeight = (items) => {
|
||||
items.style.height = items.scrollHeight + 'px'
|
||||
},
|
||||
}
|
||||
|
||||
unsetHeight (items) {
|
||||
const unsetHeight = (items) => {
|
||||
items.style.height = ''
|
||||
}
|
||||
|
||||
return { setHeight, unsetHeight }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<div class="footer-wrapper">
|
||||
<span>
|
||||
<i class="iconfont reco-theme"></i>
|
||||
<reco-icon icon="reco-theme" />
|
||||
<a target="blank" href="https://vuepress-theme-reco.recoluan.com">{{`vuepress-theme-reco@${version}`}}</a>
|
||||
</span>
|
||||
<span v-if="$themeConfig.record">
|
||||
<i class="iconfont reco-beian"></i>
|
||||
<reco-icon icon="reco-beian" />
|
||||
<a :href="$themeConfig.recordLink || '#'">{{ $themeConfig.record }}</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-copyright"></i>
|
||||
<reco-icon icon="reco-copyright" />
|
||||
<a>
|
||||
<span v-if="$themeConfig.author || $site.title">{{ $themeConfig.author || $site.title }}</span>
|
||||
<span v-if="$themeConfig.author">{{ $themeConfig.author }}</span>
|
||||
|
||||
<span v-if="$themeConfig.startYear && $themeConfig.startYear != (new Date().getFullYear())">{{ $themeConfig.startYear }} - </span>
|
||||
{{ new Date().getFullYear() }}
|
||||
</a>
|
||||
</span>
|
||||
<span v-show="showAccessNumber">
|
||||
<i class="iconfont reco-eye"></i>
|
||||
<reco-icon icon="reco-eye" />
|
||||
<AccessNumber idVal="/" />
|
||||
</span>
|
||||
<p class="cyber-security" v-if="$themeConfig.cyberSecurityRecord">
|
||||
@ -30,28 +30,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import { version } from '../package.json'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
version
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showAccessNumber () {
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const showAccessNumber = computed(() => {
|
||||
const {
|
||||
$themeConfig: { valineConfig },
|
||||
$themeLocaleConfig: { valineConfig: valineLocalConfig }
|
||||
} = this
|
||||
} = instance
|
||||
|
||||
const vc = valineLocalConfig || valineConfig
|
||||
if (vc && vc.visitor != false) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return vc && vc.visitor != false
|
||||
})
|
||||
return { version, showAccessNumber }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
@ -34,86 +34,112 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, getCurrentInstance, reactive, computed, ref, onMounted } from 'vue-demi'
|
||||
import md5 from 'md5'
|
||||
import { getOneColor } from '@theme/helpers/other'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
popupWindowStyle: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dataAddColor () {
|
||||
let { friendLink } = this.$themeConfig
|
||||
if (friendLink && friendLink.length > 0) {
|
||||
friendLink = friendLink.map(item => ({
|
||||
...item,
|
||||
color: getOneColor()
|
||||
}))
|
||||
return friendLink
|
||||
}
|
||||
return []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMd5 (str) {
|
||||
return md5(str)
|
||||
},
|
||||
showDetail (e) {
|
||||
const currentDom = e.target
|
||||
const popupWindowWrapper = currentDom.querySelector('.popup-window-wrapper')
|
||||
const popupWindow = currentDom.querySelector('.popup-window')
|
||||
popupWindowWrapper.style.display = 'block'
|
||||
const { clientWidth } = currentDom
|
||||
const {
|
||||
clientWidth: windowWidth,
|
||||
clientHeight: windowHeight
|
||||
} = popupWindow
|
||||
this.popupWindowStyle = {
|
||||
left: (clientWidth - windowWidth) / 2 + 'px',
|
||||
top: -windowHeight + 'px'
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this._adjustPosition(currentDom.querySelector('.popup-window'))
|
||||
})
|
||||
},
|
||||
hideDetail (e) {
|
||||
const currentDom = e.target
|
||||
currentDom.querySelector('.popup-window-wrapper').style.display = 'none'
|
||||
},
|
||||
getImgUrl (info) {
|
||||
const { logo, email } = info
|
||||
if (logo && /^http/.test(logo)) return logo
|
||||
if (logo && !/^http/.test(logo)) return this.$withBase(logo)
|
||||
return `//1.gravatar.com/avatar/${this.getMd5(email || '')}?s=50&d=mm&r=x`
|
||||
},
|
||||
_adjustPosition (dom) {
|
||||
const { offsetWidth } = document.body
|
||||
const { x, width } = dom.getBoundingClientRect()
|
||||
const distanceToRight = offsetWidth - (x + width)
|
||||
if (distanceToRight < 0) {
|
||||
const { offsetLeft } = dom
|
||||
this.popupWindowStyle = {
|
||||
...this.popupWindowStyle,
|
||||
left: offsetLeft + distanceToRight + 'px'
|
||||
}
|
||||
}
|
||||
const useDetail = () => {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const isPC = ref(true)
|
||||
|
||||
const popupWindowStyle = reactive({
|
||||
left: 0,
|
||||
top: 0
|
||||
})
|
||||
|
||||
const adjustPosition = (dom) => {
|
||||
const { offsetWidth } = document.body
|
||||
const { x, width } = dom.getBoundingClientRect()
|
||||
const distanceToRight = offsetWidth - (x + width)
|
||||
|
||||
if (distanceToRight < 0) {
|
||||
const { offsetLeft } = dom
|
||||
popupWindowStyle.left = offsetLeft + distanceToRight + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
const showDetail = (e) => {
|
||||
const currentDom = e.target
|
||||
const popupWindowWrapper = currentDom.querySelector('.popup-window-wrapper')
|
||||
popupWindowWrapper.style.display = 'block'
|
||||
const popupWindow = currentDom.querySelector('.popup-window')
|
||||
const infoWrapper = document.querySelector('.info-wrapper')
|
||||
const { clientWidth } = currentDom
|
||||
const { clientWidth: windowWidth, clientHeight: windowHeight } = popupWindow
|
||||
|
||||
if (isPC) {
|
||||
popupWindowStyle.left = (clientWidth - windowWidth) / 2 + 'px'
|
||||
popupWindowStyle.top = -windowHeight + 'px'
|
||||
|
||||
infoWrapper.style.overflow = 'visible'
|
||||
|
||||
instance.$nextTick(() => {
|
||||
adjustPosition(popupWindow)
|
||||
})
|
||||
} else {
|
||||
const getPosition = function (element) {
|
||||
const dc = document
|
||||
const rec = element.getBoundingClientRect()
|
||||
let _x = rec.left
|
||||
let _y = rec.top
|
||||
_x += dc.documentElement.scrollLeft || dc.body.scrollLeft
|
||||
_y += dc.documentElement.scrollTop || dc.body.scrollTop
|
||||
return { left: _x, top: _y }
|
||||
}
|
||||
|
||||
infoWrapper.style.overflow = 'hidden'
|
||||
const left = getPosition(currentDom).left - getPosition(infoWrapper).left
|
||||
|
||||
popupWindowStyle.left = (-left + (infoWrapper.clientWidth - popupWindow.clientWidth) / 2) + 'px'
|
||||
popupWindowStyle.top = -windowHeight + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
const hideDetail = (e) => {
|
||||
const currentDom = e.target.querySelector('.popup-window-wrapper')
|
||||
currentDom.style.display = 'none'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
isPC.value = !/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)
|
||||
})
|
||||
|
||||
return { popupWindowStyle, showDetail, hideDetail }
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const { popupWindowStyle, showDetail, hideDetail } = useDetail()
|
||||
|
||||
const dataAddColor = computed(() => {
|
||||
const { friendLink = [] } = instance && instance.$themeConfig
|
||||
return friendLink.map(item => {
|
||||
item.color = getOneColor()
|
||||
return item
|
||||
})
|
||||
})
|
||||
|
||||
const getImgUrl = (info) => {
|
||||
const { logo = '', email = '' } = info
|
||||
if (logo && /^http/.test(logo)) return logo
|
||||
if (logo && !/^http/.test(logo)) return instance.$withBase(logo)
|
||||
return `//1.gravatar.com/avatar/${md5(email || '')}?s=50&d=mm&r=x`
|
||||
}
|
||||
|
||||
return { dataAddColor, popupWindowStyle, showDetail, hideDetail, getImgUrl }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.friend-link-wrapper
|
||||
position relative
|
||||
margin 30px 0
|
||||
@ -151,7 +177,7 @@ export default {
|
||||
border-radius $borderRadius
|
||||
box-sizing border-box
|
||||
padding .8rem 1rem
|
||||
width 300px
|
||||
width 280px
|
||||
.logo
|
||||
margin-right .4rem
|
||||
width 2rem
|
||||
|
@ -9,7 +9,12 @@
|
||||
alt="hero">
|
||||
</ModuleTransition>
|
||||
<ModuleTransition delay="0.04">
|
||||
<h1 v-if="recoShowModule && $frontmatter.heroText !== null">{{ $frontmatter.heroText || $title || 'vuePress-theme-reco' }}</h1>
|
||||
<h1
|
||||
v-if="recoShowModule && $frontmatter.heroText !== null"
|
||||
:style="{ marginTop: $frontmatter.heroImage ? '0px' : '140px'}"
|
||||
>
|
||||
{{ $frontmatter.heroText || $title || 'vuePress-theme-reco' }}
|
||||
</h1>
|
||||
</ModuleTransition>
|
||||
<ModuleTransition delay="0.08">
|
||||
<p v-if="recoShowModule && $frontmatter.tagline !== null" class="description">
|
||||
@ -38,35 +43,31 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import NavLink from '@theme/components/NavLink'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
export default {
|
||||
mixins: [moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
components: { NavLink, ModuleTransition },
|
||||
computed: {
|
||||
|
||||
actionLink () {
|
||||
return {
|
||||
link: this.$frontmatter.actionLink,
|
||||
text: this.$frontmatter.actionText
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const recoShowModule = computed(() => instance && instance.$parent.recoShowModule)
|
||||
const actionLink = computed(() => instance && {
|
||||
link: instance.$frontmatter.actionLink,
|
||||
text: instance.$frontmatter.actionText
|
||||
})
|
||||
const heroImageStyle = computed(() => instance.$frontmatter.heroImageStyle || {
|
||||
maxHeight: '200px',
|
||||
margin: '6rem auto 1.5rem'
|
||||
})
|
||||
|
||||
heroImageStyle () {
|
||||
return this.$frontmatter.heroImageStyle || {
|
||||
maxHeight: '200px',
|
||||
margin: '6rem auto 1.5rem'
|
||||
}
|
||||
}
|
||||
return { recoShowModule, actionLink, heroImageStyle }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.home {
|
||||
padding: $navbarHeight 2rem 0;
|
||||
max-width: 960px;
|
||||
@ -75,6 +76,7 @@ export default {
|
||||
.hero {
|
||||
text-align: center;
|
||||
h1 {
|
||||
display: block;
|
||||
font-size: 2.5rem;
|
||||
color: var(--text-color);
|
||||
}
|
||||
@ -94,7 +96,7 @@ export default {
|
||||
font-size: 1.2rem;
|
||||
color: #fff;
|
||||
background-color: $accentColor;
|
||||
padding: 0.6rem 1.2rem;
|
||||
padding: 0.2rem 1.2rem;
|
||||
border-radius: $borderRadius
|
||||
transition: background-color 0.1s ease;
|
||||
box-sizing: border-box;
|
||||
@ -134,59 +136,6 @@ export default {
|
||||
transform scale(1.05)
|
||||
}
|
||||
}
|
||||
|
||||
// &.reco-hide {
|
||||
// .hero {
|
||||
// img {
|
||||
// load-start()
|
||||
// }
|
||||
// .h1 {
|
||||
// load-start()
|
||||
// }
|
||||
// .description {
|
||||
// load-start()
|
||||
// }
|
||||
// .huawei {
|
||||
// load-start()
|
||||
// }
|
||||
// .action-button {
|
||||
// load-start()
|
||||
// }
|
||||
// }
|
||||
// .features {
|
||||
// load-start()
|
||||
// }
|
||||
// .home-center {
|
||||
// load-start()
|
||||
// padding 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// &.reco-show {
|
||||
// .hero {
|
||||
// img {
|
||||
// load-end(0.08s)
|
||||
// }
|
||||
// .h1 {
|
||||
// load-end(0.16s)
|
||||
// }
|
||||
// .description {
|
||||
// load-end(0.24s)
|
||||
// }
|
||||
// .huawei {
|
||||
// load-end(0.32s)
|
||||
// }
|
||||
// .action-button {
|
||||
// load-end(0.4s)
|
||||
// }
|
||||
// }
|
||||
// .features {
|
||||
// load-end(0.40s)
|
||||
// }
|
||||
// .home-center {
|
||||
// load-end(0.48s)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobile) {
|
||||
|
8
packages/vuepress-theme-reco/components/HomeBlog/hock.js
Normal file
8
packages/vuepress-theme-reco/components/HomeBlog/hock.js
Normal file
@ -0,0 +1,8 @@
|
||||
// import { ref, reactive, toRefs, getCurrentInstance } from 'vue-demi'
|
||||
|
||||
// const useBlog = () => {
|
||||
// const currentPage = ref(1)
|
||||
// return {}
|
||||
// }
|
||||
|
||||
// export { useBlog }
|
@ -1,54 +1,40 @@
|
||||
<template>
|
||||
<div class="home-blog">
|
||||
<div class="hero" :style="{ ...bgImageStyle }">
|
||||
<div
|
||||
class="mask"
|
||||
:style="{
|
||||
background: `
|
||||
url(${$frontmatter.bgImage ?
|
||||
$withBase($frontmatter.bgImage) :
|
||||
require('../images/home-bg.jpg')}) center/cover no-repeat
|
||||
`
|
||||
}"
|
||||
></div>
|
||||
<ModuleTransition>
|
||||
<img
|
||||
v-if="recoShowModule && $frontmatter.heroImage"
|
||||
:style="heroImageStyle || {}"
|
||||
:src="$withBase($frontmatter.heroImage)"
|
||||
alt="hero"
|
||||
/>
|
||||
</ModuleTransition>
|
||||
<ModuleTransition delay="0.04">
|
||||
<h1 v-if="recoShowModule && $frontmatter.heroText !== null">
|
||||
{{ $frontmatter.heroText || $title || 'vuePress-theme-reco' }}
|
||||
</h1>
|
||||
</ModuleTransition>
|
||||
<div>
|
||||
<ModuleTransition>
|
||||
<img
|
||||
class="hero-img"
|
||||
v-if="recoShowModule && $frontmatter.heroImage"
|
||||
:style="heroImageStyle || {}"
|
||||
:src="$withBase($frontmatter.heroImage)"
|
||||
alt="hero"
|
||||
/>
|
||||
</ModuleTransition>
|
||||
|
||||
<ModuleTransition delay="0.08">
|
||||
<p v-if="recoShowModule && $frontmatter.tagline !== null" class="description">
|
||||
{{ $frontmatter.tagline || $description || 'Welcome to your vuePress-theme-reco site' }}
|
||||
</p>
|
||||
</ModuleTransition>
|
||||
<ModuleTransition delay="0.04">
|
||||
<h1 v-if="recoShowModule && $frontmatter.heroText !== null">
|
||||
{{ $frontmatter.heroText || $title || 'vuePress-theme-reco' }}
|
||||
</h1>
|
||||
</ModuleTransition>
|
||||
|
||||
<ModuleTransition delay="0.08">
|
||||
<p v-if="recoShowModule && $frontmatter.tagline !== null" class="description">
|
||||
{{ $frontmatter.tagline || $description || 'Welcome to your vuePress-theme-reco site' }}
|
||||
</p>
|
||||
</ModuleTransition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ModuleTransition delay="0.16">
|
||||
<div v-show="recoShowModule" class="home-blog-wrapper">
|
||||
<div class="blog-list">
|
||||
<!-- 博客列表 -->
|
||||
<note-abstract
|
||||
:data="$recoPosts"
|
||||
:currentPage="currentPage"></note-abstract>
|
||||
<!-- 分页 -->
|
||||
<pagation
|
||||
class="pagation"
|
||||
:total="$recoPosts.length"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage" />
|
||||
<note-abstract :data="$recoPosts" @paginationChange="paginationChange" />
|
||||
</div>
|
||||
<div class="info-wrapper">
|
||||
<PersonalInfo/>
|
||||
<h4><i class="iconfont reco-category"></i> {{homeBlogCfg.category}}</h4>
|
||||
<h4><reco-icon icon="reco-category" /> {{$recoLocales.category}}</h4>
|
||||
<ul class="category-wrapper">
|
||||
<li class="category-item" v-for="(item, index) in this.$categories.list" :key="index">
|
||||
<router-link :to="item.path">
|
||||
@ -58,9 +44,9 @@
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h4 v-if="$tags.list.length !== 0"><i class="iconfont reco-tag"></i> {{homeBlogCfg.tag}}</h4>
|
||||
<h4 v-if="$tags.list.length !== 0"><reco-icon icon="reco-tag" /> {{$recoLocales.tag}}</h4>
|
||||
<TagList @getCurrentTag="getPagesByTags" />
|
||||
<h4 v-if="$themeConfig.friendLink && $themeConfig.friendLink.length !== 0"><i class="iconfont reco-friend"></i> {{homeBlogCfg.friendLink}}</h4>
|
||||
<h4 v-if="$themeConfig.friendLink && $themeConfig.friendLink.length !== 0"><reco-icon icon="reco-friend" /> {{$recoLocales.friendLink}}</h4>
|
||||
<FriendLink />
|
||||
</div>
|
||||
</div>
|
||||
@ -73,138 +59,88 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, toRefs, reactive, computed, getCurrentInstance, onMounted } from 'vue-demi'
|
||||
import TagList from '@theme/components/TagList'
|
||||
import FriendLink from '@theme/components/FriendLink'
|
||||
import NoteAbstract from '@theme/components/NoteAbstract'
|
||||
import pagination from '@theme/mixins/pagination'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import { ModuleTransition, RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import PersonalInfo from '@theme/components/PersonalInfo'
|
||||
import { getOneColor } from '@theme/helpers/other'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [pagination, moduleTransitonMixin],
|
||||
components: { NoteAbstract, TagList, FriendLink, ModuleTransition, PersonalInfo },
|
||||
data () {
|
||||
return {
|
||||
export default defineComponent({
|
||||
components: { NoteAbstract, TagList, FriendLink, ModuleTransition, PersonalInfo, RecoIcon },
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const state = reactive({
|
||||
recoShow: false,
|
||||
currentPage: 1,
|
||||
tags: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
homeBlogCfg () {
|
||||
return this.$recoLocales.homeBlog
|
||||
},
|
||||
actionLink () {
|
||||
const {
|
||||
actionLink: link,
|
||||
actionText: text
|
||||
} = this.$frontmatter
|
||||
heroHeight: 0
|
||||
})
|
||||
|
||||
const recoShowModule = computed(() => instance && instance.$parent.recoShowModule)
|
||||
|
||||
const heroImageStyle = computed(() => instance.$frontmatter.heroImageStyle || {})
|
||||
|
||||
const bgImageStyle = computed(() => {
|
||||
const url = instance.$frontmatter.bgImage
|
||||
? instance.$withBase(instance.$frontmatter.bgImage)
|
||||
: require('../../images/bg.svg')
|
||||
|
||||
return {
|
||||
link,
|
||||
text
|
||||
}
|
||||
},
|
||||
heroImageStyle () {
|
||||
return this.$frontmatter.heroImageStyle || {
|
||||
maxHeight: '200px',
|
||||
margin: '6rem auto 1.5rem'
|
||||
}
|
||||
},
|
||||
bgImageStyle () {
|
||||
const initBgImageStyle = {
|
||||
height: '350px',
|
||||
textAlign: 'center',
|
||||
overflow: 'hidden'
|
||||
overflow: 'hidden',
|
||||
background: `url(${url}) center/cover no-repeat`
|
||||
}
|
||||
const {
|
||||
bgImageStyle
|
||||
} = this.$frontmatter
|
||||
|
||||
const { bgImageStyle } = instance.$frontmatter
|
||||
|
||||
return bgImageStyle ? { ...initBgImageStyle, ...bgImageStyle } : initBgImageStyle
|
||||
},
|
||||
heroHeight () {
|
||||
return document.querySelector('.hero').clientHeight
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.recoShow = true
|
||||
this._setPage(this._getStoragePage())
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
state.heroHeight = document.querySelector('.hero').clientHeight
|
||||
state.recoShow = true
|
||||
})
|
||||
|
||||
return { recoShowModule, heroImageStyle, bgImageStyle, ...toRefs(state), getOneColor }
|
||||
},
|
||||
methods: {
|
||||
// 获取当前页码
|
||||
getCurrentPage (page) {
|
||||
this._setPage(page)
|
||||
paginationChange (page) {
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, this.heroHeight)
|
||||
}, 100)
|
||||
},
|
||||
// 根据分类获取页面数据
|
||||
getPages () {
|
||||
let pages = this.$site.pages
|
||||
pages = pages.filter(item => {
|
||||
const { home, date } = item.frontmatter
|
||||
return !(home == true || date === undefined)
|
||||
})
|
||||
// reverse()是为了按时间最近排序排序
|
||||
this.pages = pages.length == 0 ? [] : pages
|
||||
},
|
||||
getPagesByTags (tagInfo) {
|
||||
this.$router.push({ path: tagInfo.path })
|
||||
},
|
||||
_setPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
this._setStoragePage(page)
|
||||
},
|
||||
getOneColor
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.home-blog {
|
||||
padding: $navbarHeight 0 0;
|
||||
padding: 0;
|
||||
margin: 0px auto;
|
||||
|
||||
.hero {
|
||||
margin $navbarHeight auto 0
|
||||
position relative
|
||||
.mask {
|
||||
position absolute
|
||||
top 0
|
||||
bottom 0
|
||||
left 0
|
||||
right 0
|
||||
z-index -1
|
||||
&:after {
|
||||
display block
|
||||
content ' '
|
||||
background var(--mask-color)
|
||||
position absolute
|
||||
top 0
|
||||
bottom 0
|
||||
left 0
|
||||
right 0
|
||||
z-index 0
|
||||
opacity .2
|
||||
}
|
||||
}
|
||||
figure {
|
||||
position absolute
|
||||
background yellow
|
||||
box-sizing border-box
|
||||
padding 0 20px
|
||||
height 100vh
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
.hero-img {
|
||||
max-width: 300px;
|
||||
margin: 0 auto 1.5rem
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin:7rem auto 1.8rem;
|
||||
display: block;
|
||||
margin:0 auto 1.8rem;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
h1, .description, .action, .huawei {
|
||||
color #fff
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 1.8rem auto;
|
||||
font-size: 1.6rem;
|
||||
@ -215,6 +151,7 @@ export default {
|
||||
display flex
|
||||
align-items: flex-start;
|
||||
margin 20px auto 0
|
||||
padding 0 20px
|
||||
max-width $homePageWidth
|
||||
.blog-list {
|
||||
flex auto
|
||||
@ -231,7 +168,6 @@ export default {
|
||||
top 70px
|
||||
overflow hidden
|
||||
transition all .3s
|
||||
margin-top 15px
|
||||
margin-left 15px
|
||||
flex 0 0 300px
|
||||
height auto
|
||||
@ -258,10 +194,15 @@ export default {
|
||||
background-color var(--background-color)
|
||||
&:hover {
|
||||
transform scale(1.04)
|
||||
a {
|
||||
color $accentColor
|
||||
}
|
||||
}
|
||||
a {
|
||||
display flex
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
color var(--text-color)
|
||||
.post-num {
|
||||
width 1.6rem;
|
||||
height 1.6rem
|
||||
@ -281,10 +222,7 @@ export default {
|
||||
|
||||
@media (max-width: $MQMobile) {
|
||||
.home-blog {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
.hero {
|
||||
margin 0 -1.5rem
|
||||
height 450px
|
||||
img {
|
||||
max-height: 210px;
|
||||
@ -292,14 +230,10 @@ export default {
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 6rem auto 1.8rem ;
|
||||
margin: 0 auto 1.8rem ;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h1, .description, .action {
|
||||
// margin: 1.2rem auto;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
@ -327,19 +261,15 @@ export default {
|
||||
|
||||
@media (max-width: $MQMobileNarrow) {
|
||||
.home-blog {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
|
||||
.hero {
|
||||
margin 0 -1.5rem
|
||||
height 350px
|
||||
height 450px
|
||||
img {
|
||||
max-height: 210px;
|
||||
margin: 2rem auto 1.2rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 6rem auto 1.8rem ;
|
||||
margin: 0 auto 1.8rem ;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
@ -17,14 +17,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted () {
|
||||
import { defineComponent } from 'vue-demi'
|
||||
export default defineComponent({
|
||||
setup (props, ctx) {
|
||||
const script = document.createElement('script')
|
||||
script.src = 'http://f1.webshare.mob.com/code/mob-share.js?appkey=2d1a37832f835'
|
||||
script.id = '-mob-share'
|
||||
|
||||
document.body.append(script)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -61,8 +61,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../../styles/mode.styl'
|
||||
|
||||
.mode-options
|
||||
background-color var(--background-color)
|
||||
min-width: 125px;
|
||||
@ -79,6 +77,7 @@ export default {
|
||||
display: flex;
|
||||
flex-wrap wrap
|
||||
li
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size 12px
|
||||
color var(--text-color)
|
||||
|
@ -3,10 +3,14 @@ import modeOptions from './modeOptions'
|
||||
function render (mode) {
|
||||
const rootElement = document.querySelector(':root')
|
||||
const options = modeOptions[mode]
|
||||
const opposite = mode === 'dark' ? 'light' : 'dark'
|
||||
|
||||
for (const k in options) {
|
||||
rootElement.style.setProperty(k, options[k])
|
||||
}
|
||||
|
||||
rootElement.classList.remove(opposite)
|
||||
rootElement.classList.add(mode)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<div v-click-outside="hideMenu" class="color-picker" v-if="$themeConfig.modePicker !== false" >
|
||||
<a class="color-button" @click.prevent="showMenu = !showMenu">
|
||||
<i class="iconfont reco-color"></i>
|
||||
<reco-icon icon="reco-color" />
|
||||
</a>
|
||||
<transition name="menu-transition" mode="out-in">
|
||||
<ModuleTransition :transform=" ['translate(-50%, 0)', 'translate(-50%, -10px)']">
|
||||
<div v-show="showMenu" class="color-picker-menu">
|
||||
<ModePicker />
|
||||
</div>
|
||||
</transition>
|
||||
</ModuleTransition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { RecoIcon, ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import ClickOutside from 'vue-click-outside'
|
||||
import ModePicker from './ModePicker'
|
||||
import applyMode from './applyMode'
|
||||
@ -24,7 +25,9 @@ export default {
|
||||
},
|
||||
|
||||
components: {
|
||||
ModePicker
|
||||
ModePicker,
|
||||
RecoIcon,
|
||||
ModuleTransition
|
||||
},
|
||||
|
||||
data () {
|
||||
@ -61,8 +64,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../../styles/mode.styl'
|
||||
|
||||
.color-picker {
|
||||
position: relative;
|
||||
margin-right: 1em;
|
||||
@ -80,17 +81,7 @@ export default {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 150;
|
||||
&.menu-transition-enter-active,
|
||||
&.menu-transition-leave-active {
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
&.menu-transition-enter,
|
||||
&.menu-transition-leave-to {
|
||||
top: 50px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<transition
|
||||
name="module"
|
||||
@enter="setStyle"
|
||||
@after-enter="unsetStyle"
|
||||
@before-leave="setStyle">
|
||||
<slot />
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ModuleTransition',
|
||||
|
||||
props: {
|
||||
delay: {
|
||||
type: String,
|
||||
default: '0'
|
||||
},
|
||||
duration: {
|
||||
type: String,
|
||||
default: '.25'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setStyle (items) {
|
||||
items.style.transition = `all ${this.duration}s ease-in-out ${this.delay}s`
|
||||
items.style.transform = 'translateY(-20px)'
|
||||
items.style.opacity = 0
|
||||
},
|
||||
unsetStyle (items) {
|
||||
items.style.transform = 'translateY(0)'
|
||||
items.style.opacity = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.module-enter, .module-leave-to {
|
||||
opacity: 0;
|
||||
transform:translateY(-20px);
|
||||
}
|
||||
</style>
|
@ -4,7 +4,7 @@
|
||||
:to="link"
|
||||
v-if="!isExternal(link)"
|
||||
:exact="exact">
|
||||
<i :class="`iconfont ${item.icon}`"></i>
|
||||
<reco-icon :icon="`${item.icon}`" />
|
||||
{{ item.text }}
|
||||
</router-link>
|
||||
<a
|
||||
@ -14,39 +14,41 @@
|
||||
:target="isMailto(link) || isTel(link) ? null : '_blank'"
|
||||
:rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
|
||||
>
|
||||
<i :class="`iconfont ${item.icon}`"></i>
|
||||
<reco-icon :icon="`${item.icon}`" />
|
||||
{{ item.text }}
|
||||
<OutboundLink/>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, toRefs, getCurrentInstance } from 'vue-demi'
|
||||
import { isExternal, isMailto, isTel, ensureExt } from '@theme/helpers/utils'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
|
||||
export default {
|
||||
props: {
|
||||
item: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
link () {
|
||||
return ensureExt(this.item.link)
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
exact () {
|
||||
if (this.$site.locales) {
|
||||
return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
|
||||
const { item } = toRefs(props)
|
||||
|
||||
const link = computed(() => ensureExt(item.value.link))
|
||||
|
||||
const exact = computed(() => {
|
||||
if (instance.$site.locales) {
|
||||
return Object.keys(instance.$site.locales).some(rootLink => rootLink === link.value)
|
||||
}
|
||||
return this.link === '/'
|
||||
}
|
||||
},
|
||||
return link.value === '/'
|
||||
})
|
||||
|
||||
methods: {
|
||||
isExternal,
|
||||
isMailto,
|
||||
isTel
|
||||
return { link, exact, isExternal, isMailto, isTel }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
@ -1,19 +1,13 @@
|
||||
<template>
|
||||
<nav
|
||||
class="nav-links"
|
||||
v-if="userLinks.length || repoLink"
|
||||
>
|
||||
<nav class="nav-links" v-if="userLinks.length || repoLink">
|
||||
<!-- user links -->
|
||||
<div
|
||||
class="nav-item"
|
||||
v-for="item in userLinks"
|
||||
:key="item.link">
|
||||
<DropdownLink
|
||||
v-if="item.type === 'links'"
|
||||
:item="item"/>
|
||||
<NavLink
|
||||
v-else
|
||||
:item="item"/>
|
||||
:key="item.link"
|
||||
>
|
||||
<DropdownLink v-if="item.type === 'links'" :item="item" />
|
||||
<NavLink v-else :item="item" />
|
||||
</div>
|
||||
|
||||
<!-- repo link -->
|
||||
@ -22,8 +16,9 @@
|
||||
:href="repoLink"
|
||||
class="repo-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<i :class="`iconfont reco-${repoLabel.toLowerCase()}`"></i>
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<reco-icon :icon="`reco-${repoLabel.toLowerCase()}`" />
|
||||
{{ repoLabel }}
|
||||
<OutboundLink/>
|
||||
</a>
|
||||
@ -31,36 +26,41 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import DropdownLink from '@theme/components/DropdownLink'
|
||||
import { resolveNavLinkItem } from '@theme/helpers/utils'
|
||||
import NavLink from '@theme/components/NavLink'
|
||||
|
||||
export default {
|
||||
components: { NavLink, DropdownLink },
|
||||
export default defineComponent({
|
||||
components: { NavLink, DropdownLink, RecoIcon },
|
||||
|
||||
computed: {
|
||||
userNav () {
|
||||
return this.$themeLocaleConfig.nav || this.$themeConfig.nav || []
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const userNav = computed(() => {
|
||||
return instance.$themeLocaleConfig.nav || instance.$themeConfig.nav || []
|
||||
})
|
||||
|
||||
const nav = computed(() => {
|
||||
const locales = instance.$site.locales || {}
|
||||
|
||||
nav () {
|
||||
const { $site: { locales }, userNav } = this
|
||||
if (locales && Object.keys(locales).length > 1) {
|
||||
const currentLink = this.$page.path
|
||||
const routes = this.$router.options.routes
|
||||
const themeLocales = this.$themeConfig.locales || {}
|
||||
const currentLink = instance.$page.path
|
||||
const routes = instance.$router.options.routes
|
||||
const themeLocales = instance.$themeConfig.locales || {}
|
||||
const languageDropdown = {
|
||||
text: this.$themeLocaleConfig.selectText || 'Languages',
|
||||
text: instance.$themeLocaleConfig.selectText || 'Languages',
|
||||
items: Object.keys(locales).map(path => {
|
||||
const locale = locales[path]
|
||||
const text = themeLocales[path] && themeLocales[path].label || locale.lang
|
||||
let link
|
||||
// Stay on the current page
|
||||
if (locale.lang === this.$lang) {
|
||||
if (locale.lang === instance.$lang) {
|
||||
link = currentLink
|
||||
} else {
|
||||
// Try to stay on the same page
|
||||
link = currentLink.replace(this.$localeConfig.path, path)
|
||||
link = currentLink.replace(instance.$localeConfig.path, path)
|
||||
// fallback to homepage
|
||||
if (!routes.some(route => route.path === link)) {
|
||||
link = path
|
||||
@ -69,19 +69,20 @@ export default {
|
||||
return { text, link }
|
||||
})
|
||||
}
|
||||
return [...userNav, languageDropdown]
|
||||
|
||||
return [...userNav.value, languageDropdown]
|
||||
}
|
||||
|
||||
// blogConfig 的处理,根绝配置自动添加分类和标签
|
||||
const blogConfig = this.$themeConfig.blogConfig || {}
|
||||
const isHasCategory = userNav.some(item => {
|
||||
const blogConfig = instance.$themeConfig.blogConfig || {}
|
||||
const isHasCategory = userNav.value.some(item => {
|
||||
if (blogConfig.category) {
|
||||
return item.text === (blogConfig.category.text || '分类')
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
const isHasTag = userNav.some(item => {
|
||||
const isHasTag = userNav.value.some(item => {
|
||||
if (blogConfig.tag) {
|
||||
return item.text === (blogConfig.tag.text || '标签')
|
||||
} else {
|
||||
@ -91,56 +92,59 @@ export default {
|
||||
|
||||
if (!isHasCategory && Object.hasOwnProperty.call(blogConfig, 'category')) {
|
||||
const category = blogConfig.category
|
||||
const $categories = this.$categories
|
||||
userNav.splice(parseInt(category.location || 2) - 1, 0, {
|
||||
const $categories = instance.$categories
|
||||
userNav.value.splice(parseInt(category.location || 2) - 1, 0, {
|
||||
items: $categories.list.map(item => {
|
||||
item.link = item.path
|
||||
item.text = item.name
|
||||
return item
|
||||
}),
|
||||
text: category.text || '分类',
|
||||
text: category.text || instance.$recoLocales.category,
|
||||
type: 'links',
|
||||
icon: 'reco-category'
|
||||
})
|
||||
}
|
||||
|
||||
if (!isHasTag && Object.hasOwnProperty.call(blogConfig, 'tag')) {
|
||||
const tag = blogConfig.tag
|
||||
userNav.splice(parseInt(tag.location || 3) - 1, 0, {
|
||||
userNav.value.splice(parseInt(tag.location || 3) - 1, 0, {
|
||||
link: '/tag/',
|
||||
text: tag.text || '标签',
|
||||
text: tag.text || instance.$recoLocales.tag,
|
||||
type: 'links',
|
||||
icon: 'reco-tag'
|
||||
})
|
||||
}
|
||||
|
||||
return userNav
|
||||
},
|
||||
return userNav.value
|
||||
})
|
||||
|
||||
userLinks () {
|
||||
return (this.nav || []).map(link => {
|
||||
const userLinks = computed(() => {
|
||||
return (instance.nav || []).map(link => {
|
||||
return Object.assign(resolveNavLinkItem(link), {
|
||||
items: (link.items || []).map(resolveNavLinkItem)
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const repoLink = computed(() => {
|
||||
const { repo } = instance.$themeConfig
|
||||
|
||||
repoLink () {
|
||||
const { repo } = this.$themeConfig
|
||||
if (repo) {
|
||||
return /^https?:/.test(repo)
|
||||
? repo
|
||||
: `https://github.com/${repo}`
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
repoLabel () {
|
||||
if (!this.repoLink) return
|
||||
if (this.$themeConfig.repoLabel) {
|
||||
return this.$themeConfig.repoLabel
|
||||
return ''
|
||||
})
|
||||
|
||||
const repoLabel = computed(() => {
|
||||
if (!instance.repoLink) return ''
|
||||
if (instance.$themeConfig.repoLabel) {
|
||||
return instance.$themeConfig.repoLabel
|
||||
}
|
||||
|
||||
const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
|
||||
const repoHost = instance.repoLink.match(/^https?:\/\/[^/]+/)[0]
|
||||
const platforms = ['GitHub', 'GitLab', 'Bitbucket']
|
||||
for (let i = 0; i < platforms.length; i++) {
|
||||
const platform = platforms[i]
|
||||
@ -150,9 +154,11 @@ export default {
|
||||
}
|
||||
|
||||
return 'Source'
|
||||
}
|
||||
})
|
||||
|
||||
return { userNav, nav, userLinks, repoLink, repoLabel }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@ -184,5 +190,4 @@ export default {
|
||||
.nav-item > a:not(.external)
|
||||
&:hover, &.router-link-active
|
||||
margin-bottom -2px
|
||||
border-bottom 2px solid lighten($accentColor, 8%)
|
||||
</style>
|
||||
|
@ -33,58 +33,62 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, onMounted, getCurrentInstance, computed } from 'vue-demi'
|
||||
import AlgoliaSearchBox from '@AlgoliaSearchBox'
|
||||
import SearchBox from '@SearchBox'
|
||||
import SidebarButton from '@theme/components/SidebarButton'
|
||||
import NavLinks from '@theme/components/NavLinks'
|
||||
import Mode from '@theme/components/Mode'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox, Mode },
|
||||
|
||||
data () {
|
||||
return {
|
||||
linksWrapMaxWidth: null
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const linksWrapMaxWidth = ref(null)
|
||||
|
||||
mounted () {
|
||||
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
|
||||
const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
|
||||
const handleLinksWrapWidth = () => {
|
||||
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
|
||||
this.linksWrapMaxWidth = null
|
||||
} else {
|
||||
this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING -
|
||||
(this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
|
||||
const algolia = computed(() => {
|
||||
return instance.$themeLocaleConfig.algolia || instance.$themeConfig.algolia || {}
|
||||
})
|
||||
|
||||
const isAlgoliaSearch = computed(() => {
|
||||
algolia.value && algolia.value.apiKey && algolia.value.indexName
|
||||
})
|
||||
|
||||
function css (el, property) {
|
||||
// NOTE: Known bug, will return 'auto' if style value is 'auto'
|
||||
const win = el.ownerDocument.defaultView
|
||||
// null means not to return pseudo styles
|
||||
return win.getComputedStyle(el, null)[property]
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
|
||||
const NAVBAR_VERTICAL_PADDING =
|
||||
parseInt(css(instance.$el, 'paddingLeft')) +
|
||||
parseInt(css(instance.$el, 'paddingRight'))
|
||||
|
||||
const handleLinksWrapWidth = () => {
|
||||
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
|
||||
linksWrapMaxWidth.value = null
|
||||
} else {
|
||||
linksWrapMaxWidth.value =
|
||||
instance.$el.offsetWidth -
|
||||
NAVBAR_VERTICAL_PADDING -
|
||||
(instance.$refs.siteName && instance.$refs.siteName.offsetWidth || 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
handleLinksWrapWidth()
|
||||
window.addEventListener('resize', handleLinksWrapWidth, false)
|
||||
},
|
||||
|
||||
computed: {
|
||||
algolia () {
|
||||
return this.$themeLocaleConfig.algolia || this.$themeConfig.algolia || {}
|
||||
},
|
||||
handleLinksWrapWidth()
|
||||
window.addEventListener('resize', handleLinksWrapWidth, false)
|
||||
})
|
||||
|
||||
isAlgoliaSearch () {
|
||||
return this.algolia && this.algolia.apiKey && this.algolia.indexName
|
||||
}
|
||||
return { linksWrapMaxWidth, algolia, isAlgoliaSearch, css }
|
||||
}
|
||||
}
|
||||
|
||||
function css (el, property) {
|
||||
// NOTE: Known bug, will return 'auto' if style value is 'auto'
|
||||
const win = el.ownerDocument.defaultView
|
||||
// null means not to return pseudo styles
|
||||
return win.getComputedStyle(el, null)[property]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
$navbar-vertical-padding = 0.7rem
|
||||
$navbar-horizontal-padding = 1.5rem
|
||||
|
||||
@ -106,7 +110,6 @@ $navbar-horizontal-padding = 1.5rem
|
||||
font-weight 600
|
||||
color var(--text-color)
|
||||
position relative
|
||||
background var(--background-color)
|
||||
.links
|
||||
padding-left 1.5rem
|
||||
box-sizing border-box
|
||||
|
@ -5,24 +5,59 @@
|
||||
:key="item.path"
|
||||
:item="item"
|
||||
:currentPage="currentPage"
|
||||
:currentTag="currentTag" />
|
||||
:currentTag="currentTag"
|
||||
/>
|
||||
<pagation
|
||||
class="pagation"
|
||||
:total="data.length"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, toRefs, computed, getCurrentInstance, onMounted } from 'vue-demi'
|
||||
import pagination from '@theme/mixins/pagination'
|
||||
import NoteAbstractItem from './NoteAbstractItem'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
mixins: [pagination],
|
||||
components: { NoteAbstractItem },
|
||||
props: ['data', 'currentPage', 'currentTag'],
|
||||
computed: {
|
||||
currentPageData () {
|
||||
const start = this.currentPage * 10 - 10
|
||||
const end = this.currentPage * 10
|
||||
return this.data.slice(start, end)
|
||||
props: ['data', 'currentTag'],
|
||||
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const { data } = toRefs(props)
|
||||
|
||||
const currentPage = ref(1)
|
||||
|
||||
const currentPageData = computed(() => {
|
||||
const start = (currentPage.value - 1) * instance.$perPage
|
||||
const end = currentPage.value * instance.$perPage
|
||||
|
||||
return data.value.slice(start, end)
|
||||
})
|
||||
|
||||
const getCurrentPage = (page) => {
|
||||
currentPage.value = page
|
||||
instance._setStoragePage(page)
|
||||
ctx.emit('paginationChange', page)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
currentPage.value = instance._getStoragePage() || 1
|
||||
})
|
||||
|
||||
return { currentPage, currentPageData, getCurrentPage }
|
||||
},
|
||||
watch: {
|
||||
$route () {
|
||||
this.currentPage = this._getStoragePage() || 1
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
@ -2,13 +2,12 @@
|
||||
<div
|
||||
class="abstract-item"
|
||||
@click="$router.push(item.path)">
|
||||
<i v-if="item.frontmatter.sticky" class="iconfont reco-sticky"></i>
|
||||
<reco-icon v-if="item.frontmatter.sticky" icon="reco-sticky" />
|
||||
<div class="title">
|
||||
<i v-if="item.frontmatter.keys" class="iconfont reco-lock"></i>
|
||||
<reco-icon v-if="item.frontmatter.keys" icon="reco-lock" />
|
||||
<router-link :to="item.path">{{item.title}}</router-link>
|
||||
</div>
|
||||
<div class="abstract" v-html="item.excerpt"></div>
|
||||
<hr class="hr">
|
||||
<PageInfo
|
||||
:pageInfo="item"
|
||||
:currentTag="currentTag">
|
||||
@ -17,15 +16,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import PageInfo from './PageInfo'
|
||||
export default {
|
||||
components: { PageInfo },
|
||||
export default defineComponent({
|
||||
components: { PageInfo, RecoIcon },
|
||||
props: ['item', 'currentPage', 'currentTag']
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
.abstract-item
|
||||
position relative
|
||||
margin: 0 auto 20px;
|
||||
@ -53,8 +53,10 @@ export default {
|
||||
.title
|
||||
position: relative;
|
||||
font-size: 1.28rem;
|
||||
line-height: 36px;
|
||||
line-height: 46px;
|
||||
display: inline-block;
|
||||
a
|
||||
color: var(--text-color);
|
||||
.reco-lock
|
||||
font-size 1.28rem
|
||||
color $accentColor
|
||||
|
@ -1,23 +1,19 @@
|
||||
<template>
|
||||
<main class="page" :style="pageStyle">
|
||||
<ModuleTransition>
|
||||
<div v-show="recoShowModule && $page.title" class="page-title">
|
||||
<h1>{{$page.title}}</h1>
|
||||
<hr>
|
||||
<PageInfo :pageInfo="$page" :showAccessNumber="showAccessNumber"></PageInfo>
|
||||
</div>
|
||||
</ModuleTransition>
|
||||
|
||||
<ModuleTransition delay="0.08">
|
||||
<Content v-show="recoShowModule" class="theme-reco-content" />
|
||||
<section v-show="recoShowModule">
|
||||
<div class="page-title">
|
||||
<h1 class="title">{{$page.title}}</h1>
|
||||
<PageInfo :pageInfo="$page" :showAccessNumber="showAccessNumber"></PageInfo>
|
||||
</div>
|
||||
<!-- 这里使用 v-show,否则影响 SSR -->
|
||||
<Content class="theme-reco-content" />
|
||||
</section>
|
||||
</ModuleTransition>
|
||||
|
||||
<ModuleTransition delay="0.16">
|
||||
<footer v-show="recoShowModule" class="page-edit">
|
||||
<div
|
||||
class="edit-link"
|
||||
v-if="editLink"
|
||||
>
|
||||
<footer v-if="recoShowModule" class="page-edit">
|
||||
<div class="edit-link" v-if="editLink">
|
||||
<a
|
||||
:href="editLink"
|
||||
target="_blank"
|
||||
@ -39,31 +35,15 @@
|
||||
<ModuleTransition delay="0.24">
|
||||
<div class="page-nav" v-if="recoShowModule && (prev || next)">
|
||||
<p class="inner">
|
||||
<span
|
||||
v-if="prev"
|
||||
class="prev"
|
||||
>
|
||||
←
|
||||
<router-link
|
||||
v-if="prev"
|
||||
class="prev"
|
||||
:to="prev.path"
|
||||
>
|
||||
<span v-if="prev" class="prev">
|
||||
<router-link v-if="prev" class="prev" :to="prev.path">
|
||||
{{ prev.title || prev.path }}
|
||||
</router-link>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="next"
|
||||
class="next"
|
||||
>
|
||||
<router-link
|
||||
v-if="next"
|
||||
:to="next.path"
|
||||
>
|
||||
<span v-if="next" class="next">
|
||||
<router-link v-if="next" :to="next.path">
|
||||
{{ next.title || next.path }}
|
||||
</router-link>
|
||||
→
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
@ -73,84 +53,88 @@
|
||||
<Comments v-if="recoShowModule" :isShowComments="shouldShowComments"/>
|
||||
</ModuleTransition>
|
||||
|
||||
<ModuleTransition delay="0.4">
|
||||
<SubSidebar class="side-bar" />
|
||||
<ModuleTransition>
|
||||
<SubSidebar v-if="recoShowModule" class="side-bar" />
|
||||
</ModuleTransition>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance, toRefs } from 'vue-demi'
|
||||
import PageInfo from '@theme/components/PageInfo'
|
||||
import { resolvePage, outboundRE, endingSlashRE } from '@theme/helpers/utils'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import SubSidebar from '@theme/components/SubSidebar'
|
||||
|
||||
export default {
|
||||
mixins: [moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
components: { PageInfo, ModuleTransition, SubSidebar },
|
||||
|
||||
props: ['sidebarItems'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
isHasKey: true
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const { sidebarItems } = toRefs(props)
|
||||
|
||||
const recoShowModule = computed(() => instance.$parent.recoShowModule)
|
||||
|
||||
computed: {
|
||||
// 是否显示评论
|
||||
shouldShowComments () {
|
||||
const { isShowComments } = this.$frontmatter
|
||||
const { showComment } = this.$themeConfig.valineConfig || { showComment: true }
|
||||
const shouldShowComments = computed(() => {
|
||||
const { isShowComments } = instance.$frontmatter
|
||||
const { showComment } = instance.$themeConfig.valineConfig || { showComment: true }
|
||||
return (showComment !== false && isShowComments !== false) || (showComment === false && isShowComments === true)
|
||||
},
|
||||
showAccessNumber () {
|
||||
})
|
||||
|
||||
const showAccessNumber = computed(() => {
|
||||
const {
|
||||
$themeConfig: { valineConfig },
|
||||
$themeLocaleConfig: { valineConfig: valineLocalConfig }
|
||||
} = this
|
||||
} = instance || {}
|
||||
|
||||
const vc = valineLocalConfig || valineConfig
|
||||
if (vc && vc.visitor != false) {
|
||||
return true
|
||||
|
||||
return vc && vc.visitor != false
|
||||
})
|
||||
|
||||
const lastUpdated = computed(() => {
|
||||
if (instance.$themeConfig.lastUpdated === false) return false
|
||||
return instance.$page.lastUpdated
|
||||
})
|
||||
|
||||
const lastUpdatedText = computed(() => {
|
||||
if (typeof instance.$themeLocaleConfig.lastUpdated === 'string') {
|
||||
return instance.$themeLocaleConfig.lastUpdated
|
||||
}
|
||||
return false
|
||||
},
|
||||
lastUpdated () {
|
||||
return this.$page.lastUpdated
|
||||
},
|
||||
lastUpdatedText () {
|
||||
if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
|
||||
return this.$themeLocaleConfig.lastUpdated
|
||||
}
|
||||
if (typeof this.$themeConfig.lastUpdated === 'string') {
|
||||
return this.$themeConfig.lastUpdated
|
||||
if (typeof instance.$themeConfig.lastUpdated === 'string') {
|
||||
return instance.$themeConfig.lastUpdated
|
||||
}
|
||||
return 'Last Updated'
|
||||
},
|
||||
prev () {
|
||||
const prev = this.$frontmatter.prev
|
||||
if (prev === false) {
|
||||
})
|
||||
|
||||
const prev = computed(() => {
|
||||
const frontmatterPrev = instance.$frontmatter.prev
|
||||
if (frontmatterPrev === false) {
|
||||
return
|
||||
} else if (prev) {
|
||||
return resolvePage(this.$site.pages, prev, this.$route.path)
|
||||
} else if (frontmatterPrev) {
|
||||
return resolvePage(instance.$site.pages, frontmatterPrev, instance.$route.path)
|
||||
} else {
|
||||
return resolvePrev(this.$page, this.sidebarItems)
|
||||
return resolvePrev(instance.$page, sidebarItems.value)
|
||||
}
|
||||
},
|
||||
next () {
|
||||
const next = this.$frontmatter.next
|
||||
})
|
||||
|
||||
const next = computed(() => {
|
||||
const frontmatterNext = instance.$frontmatter.next
|
||||
if (next === false) {
|
||||
return
|
||||
} else if (next) {
|
||||
return resolvePage(this.$site.pages, next, this.$route.path)
|
||||
} else if (frontmatterNext) {
|
||||
return resolvePage(instance.$site.pages, frontmatterNext, instance.$route.path)
|
||||
} else {
|
||||
return resolveNext(this.$page, this.sidebarItems)
|
||||
return resolveNext(instance.$page, sidebarItems.value)
|
||||
}
|
||||
},
|
||||
editLink () {
|
||||
if (this.$frontmatter.editLink === false) {
|
||||
})
|
||||
|
||||
const editLink = computed(() => {
|
||||
if (instance.$frontmatter.editLink === false) {
|
||||
return false
|
||||
}
|
||||
const {
|
||||
@ -159,53 +143,66 @@ export default {
|
||||
docsDir = '',
|
||||
docsBranch = 'master',
|
||||
docsRepo = repo
|
||||
} = this.$themeConfig
|
||||
} = instance.$themeConfig
|
||||
|
||||
if (docsRepo && editLinks && this.$page.relativePath) {
|
||||
return this.createEditLink(repo, docsRepo, docsDir, docsBranch, this.$page.relativePath)
|
||||
if (docsRepo && editLinks && instance.$page.relativePath) {
|
||||
return createEditLink(repo, docsRepo, docsDir, docsBranch, instance.$page.relativePath)
|
||||
}
|
||||
return ''
|
||||
},
|
||||
editLinkText () {
|
||||
return (
|
||||
this.$themeLocaleConfig.editLinkText || this.$themeConfig.editLinkText || `Edit this page`
|
||||
)
|
||||
},
|
||||
pageStyle () {
|
||||
const headers = this.$page.headers || []
|
||||
return headers.length > 0 ? {} : { paddingRight: '0' }
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
methods: {
|
||||
createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
|
||||
const bitbucket = /bitbucket.org/
|
||||
if (bitbucket.test(repo)) {
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: repo
|
||||
return (
|
||||
base.replace(endingSlashRE, '') +
|
||||
`/src` +
|
||||
`/${docsBranch}/` +
|
||||
(docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
|
||||
path +
|
||||
`?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
|
||||
)
|
||||
}
|
||||
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: `https://github.com/${docsRepo}`
|
||||
const editLinkText = computed(() => {
|
||||
return (
|
||||
base.replace(endingSlashRE, '') +
|
||||
`/edit` +
|
||||
`/${docsBranch}/` +
|
||||
(docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
|
||||
path
|
||||
instance.$themeLocaleConfig.editLinkText || instance.$themeConfig.editLinkText || `Edit this page`
|
||||
)
|
||||
})
|
||||
|
||||
const pageStyle = computed(() => {
|
||||
return instance.$showSubSideBar ? {} : { paddingRight: '0' }
|
||||
})
|
||||
|
||||
return {
|
||||
recoShowModule,
|
||||
shouldShowComments,
|
||||
showAccessNumber,
|
||||
lastUpdated,
|
||||
lastUpdatedText,
|
||||
prev,
|
||||
next,
|
||||
editLink,
|
||||
editLinkText,
|
||||
pageStyle
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
|
||||
const bitbucket = /bitbucket.org/
|
||||
if (bitbucket.test(repo)) {
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: repo
|
||||
return (
|
||||
base.replace(endingSlashRE, '') +
|
||||
`/src` +
|
||||
`/${docsBranch}/` +
|
||||
(docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
|
||||
path +
|
||||
`?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
|
||||
)
|
||||
}
|
||||
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: `https://github.com/${docsRepo}`
|
||||
|
||||
return (
|
||||
base.replace(endingSlashRE, '') +
|
||||
`/edit` +
|
||||
`/${docsBranch}/` +
|
||||
(docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
function resolvePrev (page, items) {
|
||||
@ -262,6 +259,17 @@ function flatten (items, res) {
|
||||
margin: 0 auto;
|
||||
padding: 1rem 2.5rem;
|
||||
color var(--text-color)
|
||||
.theme-reco-content h2
|
||||
position relative
|
||||
padding-left 0.8rem
|
||||
&::before
|
||||
position absolute
|
||||
left 0
|
||||
top 3.5rem
|
||||
display block
|
||||
height 1.8rem
|
||||
content ''
|
||||
border-left 5px solid $accentColor
|
||||
.page-edit
|
||||
@extend $wrapper
|
||||
padding-top 1rem
|
||||
|
@ -1,40 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<i
|
||||
class="iconfont reco-account"
|
||||
v-if="pageInfo.frontmatter.author || $themeConfig.author || $site.title">
|
||||
<span>{{ pageInfo.frontmatter.author || $themeConfig.author || $site.title }}</span>
|
||||
</i>
|
||||
<i
|
||||
<reco-icon
|
||||
v-if="pageInfo.frontmatter.author || $themeConfig.author"
|
||||
icon="reco-account"
|
||||
>
|
||||
<span>{{ pageInfo.frontmatter.author || $themeConfig.author }}</span>
|
||||
</reco-icon>
|
||||
<reco-icon
|
||||
v-if="pageInfo.frontmatter.date"
|
||||
class="iconfont reco-date">
|
||||
<span>{{ pageInfo.frontmatter.date | formatDateValue }}</span>
|
||||
</i>
|
||||
<i
|
||||
icon="reco-date"
|
||||
>
|
||||
<span>{{ formatDateValue(pageInfo.frontmatter.date) }}</span>
|
||||
</reco-icon>
|
||||
<reco-icon
|
||||
v-if="showAccessNumber === true"
|
||||
class="iconfont reco-eye">
|
||||
<AccessNumber
|
||||
:idVal="pageInfo.path"
|
||||
:numStyle="numStyle" />
|
||||
</i>
|
||||
<i
|
||||
icon="reco-eye"
|
||||
>
|
||||
<AccessNumber :idVal="pageInfo.path" :numStyle="numStyle" />
|
||||
</reco-icon>
|
||||
<reco-icon
|
||||
v-if="pageInfo.frontmatter.tags"
|
||||
class="iconfont reco-tag tags">
|
||||
icon="reco-tag"
|
||||
class="tags"
|
||||
>
|
||||
<span
|
||||
v-for="(subItem, subIndex) in pageInfo.frontmatter.tags"
|
||||
:key="subIndex"
|
||||
class="tag-item"
|
||||
:class="{ 'active': currentTag == subItem }"
|
||||
@click.stop="goTags(subItem)">{{subItem}}</span>
|
||||
</i>
|
||||
@click.stop="goTags(subItem)"
|
||||
>{{subItem}}</span>
|
||||
</reco-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入时间格式化js文件
|
||||
import { formatDate } from '@theme/helpers/utils'
|
||||
import { defineComponent, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
props: {
|
||||
pageInfo: {
|
||||
type: Object,
|
||||
@ -51,44 +56,29 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
numStyle: {
|
||||
fontSize: '.9rem',
|
||||
fontWeight: 'normal',
|
||||
color: '#999'
|
||||
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const numStyle = {
|
||||
fontSize: '.9rem',
|
||||
fontWeight: 'normal',
|
||||
color: '#999'
|
||||
}
|
||||
|
||||
const goTags = (tag) => {
|
||||
if (instance.$route.path !== `/tag/${tag}/`) {
|
||||
instance.$router.push({ path: `/tag/${tag}/` })
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatDateValue (value) {
|
||||
if (!value) return ''
|
||||
// 返回的value的值都是这个样子2019-09-20T18:22:30.000Z
|
||||
// 对value进行处理
|
||||
value = value.replace('T', ' ').slice(0, value.lastIndexOf('.'))
|
||||
// 转化后的value 2019-09-20 18:22:30
|
||||
// 获取到时分秒
|
||||
const h = Number(value.substr(11, 2))
|
||||
const m = Number(value.substr(14, 2))
|
||||
const s = Number(value.substr(17, 2))
|
||||
// 判断时分秒是不是 00:00:00 (如果是用户手动输入的00:00:00也会不显示)
|
||||
if (h > 0 || m > 0 || s > 0) {
|
||||
// 时分秒有一个> 0 就说明用户输入一个非 00:00:00 的时分秒
|
||||
return formatDate(value)
|
||||
} else {
|
||||
// 用户没有输入或者输入了 00:00:00
|
||||
return formatDate(value, 'yyyy-MM-dd')
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goTags (tag) {
|
||||
if (this.$route.path !== `/tag/${tag}/`) {
|
||||
this.$router.push({ path: `/tag/${tag}/` })
|
||||
}
|
||||
|
||||
const formatDateValue = (value) => {
|
||||
return new Intl.DateTimeFormat(instance.$lang).format(new Date(value))
|
||||
}
|
||||
|
||||
return { numStyle, goTags, formatDateValue }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@ -102,6 +92,7 @@ export default {
|
||||
.tags
|
||||
.tag-item
|
||||
font-family Ubuntu, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif
|
||||
cursor pointer
|
||||
&.active
|
||||
color $accentColor
|
||||
&:hover
|
||||
|
@ -24,13 +24,13 @@
|
||||
<ModuleTransition delay="0.24">
|
||||
<div v-show="recoShowModule" class="footer">
|
||||
<span>
|
||||
<i class="iconfont reco-theme"></i>
|
||||
<reco-icon icon="reco-theme" />
|
||||
<a target="blank" href="https://vuepress-theme-reco.recoluan.com">vuePress-theme-reco</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-copyright"></i>
|
||||
<reco-icon icon="reco-copyright" />
|
||||
<a>
|
||||
<span v-if="$themeConfig.author || $site.title">{{ $themeConfig.author || $site.title }}</span>
|
||||
<span v-if="$themeConfig.author">{{ $themeConfig.author }}</span>
|
||||
|
||||
<span v-if="$themeConfig.startYear && $themeConfig.startYear != year">{{ $themeConfig.startYear }} - </span>
|
||||
{{ year }}
|
||||
@ -42,84 +42,78 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, toRefs, computed, getCurrentInstance } from 'vue-demi'
|
||||
import md5 from 'md5'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
import { ModuleTransition, RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
export default {
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { ModuleTransition },
|
||||
export default defineComponent({
|
||||
name: 'Password',
|
||||
components: { ModuleTransition, RecoIcon },
|
||||
props: {
|
||||
isPage: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
name: 'Password',
|
||||
data () {
|
||||
return {
|
||||
warningText: 'Konck! Knock!',
|
||||
key: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
year () {
|
||||
return new Date().getFullYear()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
inter () {
|
||||
const {
|
||||
key,
|
||||
isPage,
|
||||
isHasPageKey,
|
||||
isHasKey,
|
||||
$refs: { passwordBtn }
|
||||
} = this
|
||||
const keyVal = md5(key.trim())
|
||||
const pageKey = `pageKey${window.location.pathname}`
|
||||
const keyName = isPage ? pageKey : 'key'
|
||||
sessionStorage.setItem(keyName, keyVal)
|
||||
const isKeyTrue = isPage ? isHasPageKey() : isHasKey()
|
||||
if (!isKeyTrue) {
|
||||
this.warningText = 'Key Error'
|
||||
return
|
||||
}
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
this.warningText = 'Key Success'
|
||||
const year = new Date().getFullYear()
|
||||
|
||||
const width = document.getElementById('box').style.width
|
||||
const key = ref('')
|
||||
const warningText = ref('Konck! Knock!')
|
||||
const recoShowModule = computed(() => instance?.$parent?.recoShowModule)
|
||||
const { isPage } = toRefs(props)
|
||||
|
||||
passwordBtn.style.width = `${width - 2}px`
|
||||
passwordBtn.style.opacity = 1
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 800)
|
||||
},
|
||||
inputFocus () {
|
||||
this.warningText = 'Input Your Key'
|
||||
},
|
||||
inputBlur () {
|
||||
this.warningText = 'Konck! Knock!'
|
||||
},
|
||||
isHasKey () {
|
||||
let { keys } = this.$themeConfig.keyPage
|
||||
const isHasKey = () => {
|
||||
let { keys } = instance.$themeConfig.keyPage
|
||||
keys = keys.map(item => item.toLowerCase())
|
||||
return keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
},
|
||||
isHasPageKey () {
|
||||
const pageKeys = this.$frontmatter.keys.map(item => item.toLowerCase())
|
||||
}
|
||||
const isHasPageKey = () => {
|
||||
const pageKeys = instance.$frontmatter.keys.map(item => item.toLowerCase())
|
||||
const pageKey = `pageKey${window.location.pathname}`
|
||||
|
||||
return pageKeys && pageKeys.indexOf(sessionStorage.getItem(pageKey)) > -1
|
||||
}
|
||||
|
||||
const inter = () => {
|
||||
const keyVal = md5(key.value.trim())
|
||||
const pageKey = `pageKey${window.location.pathname}`
|
||||
const keyName = isPage.value ? pageKey : 'key'
|
||||
sessionStorage.setItem(keyName, keyVal)
|
||||
const isKeyTrue = isPage.value ? isHasPageKey() : isHasKey()
|
||||
if (!isKeyTrue) {
|
||||
warningText.value = 'Key Error'
|
||||
return
|
||||
}
|
||||
|
||||
warningText.value = 'Key Success'
|
||||
|
||||
const width = document.getElementById('box').style.width
|
||||
|
||||
instance.$refs.passwordBtn.style.width = `${width - 2}px`
|
||||
instance.$refs.passwordBtn.style.opacity = 1
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 800)
|
||||
}
|
||||
|
||||
const inputFocus = () => {
|
||||
warningText.value = 'Input Your Key'
|
||||
}
|
||||
|
||||
const inputBlur = () => {
|
||||
warningText.value = 'Konck! Knock!'
|
||||
}
|
||||
|
||||
return { warningText, year, key, recoShowModule, inter, inputFocus, inputBlur }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.password-shadow {
|
||||
overflow hidden
|
||||
position relative
|
||||
@ -161,7 +155,7 @@ export default {
|
||||
box-sizing border-box
|
||||
opacity 0.9
|
||||
input{
|
||||
width:600px;
|
||||
width:570px;
|
||||
height:100%;
|
||||
border:none;
|
||||
padding:0;
|
||||
|
@ -8,32 +8,50 @@
|
||||
>
|
||||
<h3
|
||||
class="name"
|
||||
v-if="$themeConfig.author || $site.title"
|
||||
v-if="$themeConfig.author"
|
||||
>
|
||||
{{ $themeConfig.author || $site.title }}
|
||||
{{ $themeConfig.author }}
|
||||
</h3>
|
||||
<div class="num">
|
||||
<div>
|
||||
<h3>{{$recoPosts.length}}</h3>
|
||||
<h6>{{homeBlogCfg.article}}</h6>
|
||||
<h6>{{$recoLocales.article}}</h6>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{{$tags.list.length}}</h3>
|
||||
<h6>{{homeBlogCfg.tag}}</h6>
|
||||
<h6>{{$recoLocales.tag}}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="social-links">
|
||||
<li
|
||||
class="social-item"
|
||||
v-for="(item, index) in socialLinks"
|
||||
:key="index"
|
||||
>
|
||||
<reco-icon :icon="item.icon" :link="item.link" :style="{ color: item.color }" />
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
homeBlogCfg () {
|
||||
return this.$recoLocales.homeBlog
|
||||
}
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
import { getOneColor } from '@theme/helpers/other'
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const socialLinks = computed(() => (instance.$themeConfig.blogConfig && instance.$themeConfig.blogConfig.socialLinks || []).map(item => {
|
||||
if (!item.color) item.color = getOneColor()
|
||||
return item
|
||||
}))
|
||||
|
||||
return { socialLinks }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@ -72,5 +90,26 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.social-links {
|
||||
box-sizing border-box
|
||||
display flex
|
||||
flex-wrap wrap
|
||||
padding 10px
|
||||
.social-item {
|
||||
width 39px
|
||||
height 36px
|
||||
line-height 36px
|
||||
text-align center
|
||||
list-style none
|
||||
transition transform .3s
|
||||
&:hover {
|
||||
transform scale(1.08)
|
||||
}
|
||||
i {
|
||||
cursor pointer
|
||||
font-size 22px
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="search-box">
|
||||
<i class="iconfont reco-search"></i>
|
||||
<reco-icon icon="reco-search" />
|
||||
<input
|
||||
@input="query = $event.target.value"
|
||||
aria-label="Search"
|
||||
@ -40,32 +40,44 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
import { defineComponent, reactive, toRefs, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { RecoIcon } from '@vuepress-reco/core/lib/components'
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecoIcon },
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const state = reactive({
|
||||
query: '',
|
||||
focused: false,
|
||||
focusIndex: 0,
|
||||
placeholder: undefined
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
|
||||
},
|
||||
computed: {
|
||||
showSuggestions () {
|
||||
})
|
||||
|
||||
const showSuggestions = computed(() => {
|
||||
return (
|
||||
this.focused && this.suggestions && this.suggestions.length
|
||||
state.focused && suggestions.value && suggestions.value.length
|
||||
)
|
||||
},
|
||||
suggestions () {
|
||||
const query = this.query.trim().toLowerCase()
|
||||
})
|
||||
|
||||
const getPageLocalePath = (page) => {
|
||||
for (const localePath in instance.$site.locales || {}) {
|
||||
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
|
||||
return localePath
|
||||
}
|
||||
}
|
||||
return '/'
|
||||
}
|
||||
|
||||
const suggestions = computed(() => {
|
||||
const query = state.query.trim().toLowerCase()
|
||||
if (!query) {
|
||||
return
|
||||
}
|
||||
const { pages } = this.$site
|
||||
const max = this.$site.themeConfig.searchMaxSuggestions
|
||||
const localePath = this.$localePath
|
||||
const { pages } = instance.$site
|
||||
const max = instance.$site.themeConfig.searchMaxSuggestions
|
||||
const localePath = instance.$localePath
|
||||
const matches = item => (
|
||||
item && item.title && item.title.toLowerCase().indexOf(query) > -1
|
||||
)
|
||||
@ -74,7 +86,7 @@ export default {
|
||||
if (res.length >= max) break
|
||||
const p = pages[i]
|
||||
// filter out results that do not match current locale
|
||||
if (this.getPageLocalePath(p) !== localePath) {
|
||||
if (getPageLocalePath(p) !== localePath) {
|
||||
continue
|
||||
}
|
||||
if (matches(p)) {
|
||||
@ -93,57 +105,57 @@ export default {
|
||||
}
|
||||
}
|
||||
return res
|
||||
},
|
||||
// make suggestions align right when there are not enough items
|
||||
alignRight () {
|
||||
const navCount = (this.$site.themeConfig.nav || []).length
|
||||
const repo = this.$site.repo ? 1 : 0
|
||||
})
|
||||
|
||||
const alignRight = computed(() => {
|
||||
const navCount = (instance.$site.themeConfig.nav || []).length
|
||||
const repo = instance.$site.repo ? 1 : 0
|
||||
return navCount + repo <= 2
|
||||
})
|
||||
|
||||
const onUp = () => {
|
||||
if (showSuggestions.value) {
|
||||
if (state.focusIndex > 0) {
|
||||
state.focusIndex--
|
||||
} else {
|
||||
state.focusIndex = suggestions.value.length - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getPageLocalePath (page) {
|
||||
for (const localePath in this.$site.locales || {}) {
|
||||
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
|
||||
return localePath
|
||||
}
|
||||
}
|
||||
return '/'
|
||||
},
|
||||
onUp () {
|
||||
if (this.showSuggestions) {
|
||||
if (this.focusIndex > 0) {
|
||||
this.focusIndex--
|
||||
|
||||
const onDown = () => {
|
||||
if (showSuggestions.value) {
|
||||
if (state.focusIndex < suggestions.value.length - 1) {
|
||||
state.focusIndex++
|
||||
} else {
|
||||
this.focusIndex = this.suggestions.length - 1
|
||||
state.focusIndex = 0
|
||||
}
|
||||
}
|
||||
},
|
||||
onDown () {
|
||||
if (this.showSuggestions) {
|
||||
if (this.focusIndex < this.suggestions.length - 1) {
|
||||
this.focusIndex++
|
||||
} else {
|
||||
this.focusIndex = 0
|
||||
}
|
||||
}
|
||||
},
|
||||
go (i) {
|
||||
if (!this.showSuggestions) {
|
||||
}
|
||||
|
||||
const go = (i) => {
|
||||
if (!showSuggestions.value) {
|
||||
return
|
||||
}
|
||||
this.$router.push(this.suggestions[i].path)
|
||||
this.query = ''
|
||||
this.focusIndex = 0
|
||||
},
|
||||
focus (i) {
|
||||
this.focusIndex = i
|
||||
},
|
||||
unfocus () {
|
||||
this.focusIndex = -1
|
||||
instance.$router.push(suggestions.value[i].path)
|
||||
state.query = ''
|
||||
state.focusIndex = 0
|
||||
}
|
||||
|
||||
const focus = (i) => {
|
||||
state.focusIndex = i
|
||||
}
|
||||
|
||||
const unfocus = () => {
|
||||
state.focusIndex = -1
|
||||
}
|
||||
|
||||
return { showSuggestions, suggestions, alignRight, onUp, onDown, focus, unfocus, go, ...toRefs(state) }
|
||||
},
|
||||
mounted () {
|
||||
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -8,16 +8,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue-demi'
|
||||
import SidebarLinks from '@theme/components/SidebarLinks'
|
||||
import NavLinks from '@theme/components/NavLinks'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Sidebar',
|
||||
|
||||
components: { SidebarLinks, NavLinks },
|
||||
|
||||
props: ['items']
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -54,19 +54,23 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, getCurrentInstance } from 'vue-demi'
|
||||
import { isActive } from '@theme/helpers/utils'
|
||||
import DropdownTransition from '@theme/components/DropdownTransition'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'SidebarGroup',
|
||||
props: ['item', 'open', 'collapsable', 'depth'],
|
||||
components: { DropdownTransition },
|
||||
// ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
||||
beforeCreate () {
|
||||
this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
|
||||
},
|
||||
methods: { isActive }
|
||||
}
|
||||
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
instance.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
|
||||
|
||||
return { isActive }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -1,7 +1,8 @@
|
||||
<script>
|
||||
import { defineComponent } from 'vue-demi'
|
||||
import { isActive } from '@theme/helpers/utils'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
functional: true,
|
||||
|
||||
props: ['item', 'sidebarDepth'],
|
||||
@ -30,27 +31,8 @@ export default {
|
||||
: selfActive
|
||||
const link = renderLink(h, item.path, item.title || item.path, active)
|
||||
return link
|
||||
|
||||
// const configDepth = $page.frontmatter.sidebarDepth ||
|
||||
// sidebarDepth ||
|
||||
// $themeLocaleConfig.sidebarDepth ||
|
||||
// $themeConfig.sidebarDepth
|
||||
|
||||
// const maxDepth = configDepth == null ? 1 : configDepth
|
||||
|
||||
// const displayAllHeaders = $themeLocaleConfig.displayAllHeaders ||
|
||||
// $themeConfig.displayAllHeaders
|
||||
|
||||
// if (item.type === 'auto') {
|
||||
// return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
|
||||
// } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
|
||||
// const children = groupHeaders(item.headers)
|
||||
// return [link, renderChildren(h, children, item.path, $route, maxDepth)]
|
||||
// } else {
|
||||
// return link
|
||||
// }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function renderLink (h, to, text, active) {
|
||||
return h('router-link', {
|
||||
|
@ -22,11 +22,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, getCurrentInstance, toRefs, onUpdated, onMounted } from 'vue-demi'
|
||||
import SidebarGroup from '@theme/components/SidebarGroup'
|
||||
import SidebarLink from '@theme/components/SidebarLink'
|
||||
import { isActive } from '@theme/helpers/utils'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'SidebarLinks',
|
||||
|
||||
components: { SidebarGroup, SidebarLink },
|
||||
@ -37,57 +38,48 @@ export default {
|
||||
'sidebarDepth' // depth of headers to be extracted
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
openGroupIndex: 0
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const { items } = toRefs(props)
|
||||
|
||||
const openGroupIndex = ref(0)
|
||||
|
||||
const refreshIndex = () => {
|
||||
const index = resolveOpenGroupIndex(
|
||||
instance.$route,
|
||||
items.value
|
||||
)
|
||||
if (index > -1) {
|
||||
openGroupIndex.value = index
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.refreshIndex()
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route' () {
|
||||
this.refreshIndex()
|
||||
const activationAnchor = () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const anchors = [].slice.call(document.querySelectorAll(AHL_HEADER_ANCHOR_SELECTOR))
|
||||
.filter(anchor => decodeURIComponent(instance.$route.fullPath).indexOf(decodeURIComponent(anchor.hash)) != -1)
|
||||
if (anchors == null || anchors.length < 1 || anchors[0].offsetTop == undefined) return
|
||||
setTimeout(function () {
|
||||
window.scrollTo(0, anchors[0].offsetTop + 160)
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.activationLink()
|
||||
this.isInViewPortOfOne()
|
||||
},
|
||||
|
||||
updated: function () {
|
||||
this.isInViewPortOfOne()
|
||||
},
|
||||
|
||||
methods: {
|
||||
activationLink () {
|
||||
const subtitleName = decodeURIComponent(this.$route.fullPath)
|
||||
const activationLink = () => {
|
||||
const subtitleName = decodeURIComponent(instance.$route.fullPath)
|
||||
if (!subtitleName || subtitleName == '') return
|
||||
// eslint-disable-next-line no-undef
|
||||
const subtitles = [].slice.call(document.querySelectorAll(AHL_SIDEBAR_LINK_SELECTOR))
|
||||
for (let i = 0; i < subtitles.length; i++) {
|
||||
if (decodeURIComponent(subtitles[i].getAttribute('href')).indexOf(subtitleName) != -1) {
|
||||
subtitles[i].click()
|
||||
this.activationAnchor()
|
||||
activationAnchor()
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
activationAnchor () {
|
||||
// eslint-disable-next-line no-undef
|
||||
const anchors = [].slice.call(document.querySelectorAll(AHL_HEADER_ANCHOR_SELECTOR))
|
||||
.filter(anchor => decodeURIComponent(this.$route.fullPath).indexOf(decodeURIComponent(anchor.hash)) != -1)
|
||||
if (anchors == null || anchors.length < 1 || anchors[0].offsetTop == undefined) return
|
||||
setTimeout(function () {
|
||||
window.scrollTo(0, anchors[0].offsetTop + 160)
|
||||
}, 100)
|
||||
},
|
||||
|
||||
isInViewPortOfOne () {
|
||||
const isInViewPortOfOne = () => {
|
||||
const sidebarScroll = document.getElementsByClassName('sidebar')[0]
|
||||
let el = document.getElementsByClassName('active sidebar-link')[1]
|
||||
if (el == null || el == undefined || el.offsetTop == undefined) {
|
||||
@ -107,27 +99,34 @@ export default {
|
||||
if (!topVisible) {
|
||||
sidebarScroll.scrollTop = (offsetTop - 5)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
refreshIndex () {
|
||||
const index = resolveOpenGroupIndex(
|
||||
this.$route,
|
||||
this.items
|
||||
)
|
||||
if (index > -1) {
|
||||
this.openGroupIndex = index
|
||||
}
|
||||
},
|
||||
const toggleGroup = (index) => {
|
||||
instance.openGroupIndex = index === instance.openGroupIndex ? -1 : index
|
||||
}
|
||||
|
||||
toggleGroup (index) {
|
||||
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
|
||||
},
|
||||
const isActive = (page) => {
|
||||
return isActive(instance.$route, page.regularPath)
|
||||
}
|
||||
|
||||
isActive (page) {
|
||||
return isActive(this.$route, page.regularPath)
|
||||
refreshIndex()
|
||||
|
||||
onMounted(() => {
|
||||
activationLink()
|
||||
isInViewPortOfOne()
|
||||
})
|
||||
|
||||
onUpdated(() => isInViewPortOfOne())
|
||||
|
||||
return { openGroupIndex, refreshIndex, toggleGroup, isActive }
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route' () {
|
||||
this.refreshIndex()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function resolveOpenGroupIndex (route, items) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
@ -1,24 +1,33 @@
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { isActive } from '@theme/helpers/utils'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
headers () {
|
||||
const headers = (this.$page.headers || []).filter(header => header.level === 2)
|
||||
return headers
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isLinkActive (header) {
|
||||
return isActive(this.$route, this.$page.path + '#' + header.slug)
|
||||
export default defineComponent({
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const headers = computed(() => {
|
||||
return instance.$showSubSideBar ? instance.$page.headers : []
|
||||
})
|
||||
|
||||
const isLinkActive = (header) => {
|
||||
const active = isActive(instance.$route, instance.$page.path + '#' + header.slug)
|
||||
if (active) {
|
||||
setTimeout(() => {
|
||||
document.querySelector(`.reco-side-${header.slug}`).scrollIntoView()
|
||||
}, 300)
|
||||
}
|
||||
return active
|
||||
}
|
||||
|
||||
return { headers, isLinkActive }
|
||||
},
|
||||
render (h) {
|
||||
return h('ul', {
|
||||
class: { 'sub-sidebar-wrapper': true },
|
||||
style: { width: (this.$page.headers || []).length > 0 ? '12rem' : '0' }
|
||||
style: { width: this.headers.length > 0 ? '12rem' : '0' }
|
||||
}, [
|
||||
...(this.$page.headers || []).map(header => {
|
||||
...this.headers.map(header => {
|
||||
return h('li', {
|
||||
class: {
|
||||
active: this.isLinkActive(header),
|
||||
@ -27,15 +36,14 @@ export default {
|
||||
attr: { key: header.title }
|
||||
}, [
|
||||
h('router-link', {
|
||||
class: { 'sidebar-link': true },
|
||||
class: { 'sidebar-link': true, [`reco-side-${header.slug}`]: true },
|
||||
props: { to: `${this.$page.path}#${header.slug}` }
|
||||
}, header.title)
|
||||
])
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
@ -2,6 +2,7 @@
|
||||
<div class="tags">
|
||||
<span
|
||||
v-for="(item, index) in tags"
|
||||
v-show="!item.pages || (item.pages && item.pages.length > 0)"
|
||||
:key="index"
|
||||
:class="{'active': item.name == currentTag}"
|
||||
:style="{ 'backgroundColor': getOneColor() }"
|
||||
@ -10,32 +11,32 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import { getOneColor } from '@theme/helpers/other'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
props: {
|
||||
currentTag: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tags () {
|
||||
return [{ name: '全部', path: '/tag/' }, ...this.$tags.list]
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
const tags = computed(() => {
|
||||
return [{ name: instance.$recoLocales.all, path: '/tag/' }, ...instance.$tagesList]
|
||||
})
|
||||
|
||||
const tagClick = tag => {
|
||||
ctx.emit('getCurrentTag', tag)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
tagClick (tag) {
|
||||
this.$emit('getCurrentTag', tag)
|
||||
},
|
||||
getOneColor
|
||||
|
||||
return { tags, tagClick, getOneColor }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.tags
|
||||
margin 30px 0
|
||||
span
|
||||
|
@ -1,17 +1,25 @@
|
||||
/* eslint-disable no-proto */
|
||||
import postMixin from '@theme/mixins/posts'
|
||||
import localMixin from '@theme/mixins/locales'
|
||||
import { addLinkToHead } from '@theme/helpers/utils'
|
||||
import { registerCodeThemeCss } from '@theme/helpers/other'
|
||||
import { addLinkToHead, addScriptToHead } from '@theme/helpers/utils'
|
||||
import { registerCodeThemeCss, interceptRouterError, fixRouterError404 } from '@theme/helpers/other'
|
||||
import { install } from 'vue-demi'
|
||||
|
||||
export default ({
|
||||
Vue,
|
||||
siteData,
|
||||
isServer
|
||||
isServer,
|
||||
router
|
||||
}) => {
|
||||
install(Vue)
|
||||
Vue.mixin(postMixin)
|
||||
Vue.mixin(localMixin)
|
||||
if (!isServer) {
|
||||
addLinkToHead('//at.alicdn.com/t/font_1030519_2ciwdtb4x65.css')
|
||||
addScriptToHead('//kit.fontawesome.com/51b01de608.js')
|
||||
registerCodeThemeCss(siteData.themeConfig.codeTheme)
|
||||
}
|
||||
|
||||
interceptRouterError(router)
|
||||
fixRouterError404(router)
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<script>
|
||||
export default {
|
||||
import { defineComponent } from 'vue-demi'
|
||||
|
||||
export default defineComponent({
|
||||
functional: true,
|
||||
props: {
|
||||
type: {
|
||||
@ -20,11 +22,10 @@ export default {
|
||||
}
|
||||
}, props.text || slots().default)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
.badge
|
||||
display inline-block
|
||||
font-size 14px
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-proto */
|
||||
import { addLinkToHead } from './utils'
|
||||
export function getOneColor () {
|
||||
const tagColorArr = [
|
||||
@ -24,3 +25,27 @@ export function registerCodeThemeCss (theme = 'tomorrow') {
|
||||
|
||||
addLinkToHead(href)
|
||||
}
|
||||
|
||||
export function interceptRouterError (router) {
|
||||
// 获取原型对象上的 push 函数
|
||||
const originalPush = router.__proto__.push
|
||||
// 修改原型对象中的p ush 方法
|
||||
router.__proto__.push = function push (location) {
|
||||
return originalPush.call(this, location).catch(err => err)
|
||||
}
|
||||
}
|
||||
|
||||
export function fixRouterError404 (router) {
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 解决非ASCII文件名的路由, 防止 404
|
||||
const decodedPath = decodeURIComponent(to.path)
|
||||
if (decodedPath !== to.path) {
|
||||
next(Object.assign({}, to, {
|
||||
fullPath: decodeURIComponent(to.fullPath),
|
||||
path: decodedPath
|
||||
}))
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export function filterPosts (posts, isTimeline) {
|
||||
if (posts.indexOf(item) !== index) {
|
||||
return false
|
||||
} else {
|
||||
const someConditions = home == true || title == undefined || publish === false
|
||||
const someConditions = home === true || title == undefined || publish === false
|
||||
const boo = isTimeline === true
|
||||
? !(someConditions || date === undefined)
|
||||
: !someConditions
|
||||
|
@ -122,21 +122,6 @@ export function resolveSidebarItems (page, regularPath, site, localePath) {
|
||||
? themeConfig.locales[localePath] || themeConfig
|
||||
: themeConfig
|
||||
|
||||
// 计算页面的菜单层级
|
||||
// const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar
|
||||
// if (pageSidebarConfig === 'auto') {
|
||||
// return resolveHeaders(page)
|
||||
// }
|
||||
|
||||
// const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar
|
||||
// if (!sidebarConfig) {
|
||||
// return []
|
||||
// } else {
|
||||
// const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig)
|
||||
// return config
|
||||
// ? config.map(item => resolveItem(item, pages, base))
|
||||
// : []
|
||||
// }
|
||||
const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar
|
||||
|
||||
const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig)
|
||||
@ -145,27 +130,6 @@ export function resolveSidebarItems (page, regularPath, site, localePath) {
|
||||
: []
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Page } page
|
||||
* @returns { SidebarGroup }
|
||||
*/
|
||||
// function resolveHeaders (page) {
|
||||
// const headers = groupHeaders(page.headers || [])
|
||||
// return [{
|
||||
// type: 'group',
|
||||
// collapsable: false,
|
||||
// title: page.title,
|
||||
// path: null,
|
||||
// children: headers.map(h => ({
|
||||
// type: 'auto',
|
||||
// title: h.title,
|
||||
// basePath: page.path,
|
||||
// path: page.path + '#' + h.slug,
|
||||
// children: h.children || []
|
||||
// }))
|
||||
// }]
|
||||
// }
|
||||
|
||||
export function groupHeaders (headers) {
|
||||
// group h3s under h2
|
||||
headers = headers.map(h => Object.assign({}, h))
|
||||
@ -235,12 +199,16 @@ export function formatDate (time, fmt = 'yyyy-MM-dd hh:mm:ss') {
|
||||
|
||||
// 获取时间的数字类型
|
||||
export function getTimeNum (date) {
|
||||
return new Date(date.frontmatter.date).getTime()
|
||||
const dateNum = !date ? 0 : new Date(date).getTime()
|
||||
return dateNum
|
||||
}
|
||||
|
||||
// 比对时间
|
||||
export function compareDate (a, b) {
|
||||
return getTimeNum(b) - getTimeNum(a)
|
||||
const aDateNum = getTimeNum(a.frontmatter.date)
|
||||
const bDateNum = getTimeNum(b.frontmatter.date)
|
||||
if (aDateNum === 0 || bDateNum === 0) return 0
|
||||
return bDateNum - aDateNum
|
||||
}
|
||||
|
||||
// 向 head 中添加 style
|
||||
@ -252,6 +220,14 @@ export function addLinkToHead (href) {
|
||||
document.head.append(iconLink)
|
||||
}
|
||||
|
||||
// 向 head 中添加 script
|
||||
export function addScriptToHead (href) {
|
||||
const iconLink = document.createElement('script')
|
||||
iconLink.src = href
|
||||
|
||||
document.head.append(iconLink)
|
||||
}
|
||||
|
||||
function ensureEndingSlash (path) {
|
||||
return /(\.html|\/)$/.test(path)
|
||||
? path
|
||||
|
39
packages/vuepress-theme-reco/images/bg.svg
Normal file
39
packages/vuepress-theme-reco/images/bg.svg
Normal file
@ -0,0 +1,39 @@
|
||||
<svg
|
||||
version="1.1"
|
||||
baseProfile="full"
|
||||
width="100%" height="100%"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1400 800"
|
||||
>
|
||||
|
||||
<rect x="1300" y="400" rx="40" ry="40" width="300" height="300" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
|
||||
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 1450 550" to="360 1450 550" repeatCount="indefinite" />
|
||||
</rect>
|
||||
|
||||
<path d="M 100 350 A 150 150 0 1 1 400 350 Q400 370 380 370 L 250 370 L 120 370 Q100 370 100 350" stroke="rgb(253, 214, 99)" fill="rgb(253, 214, 99)">
|
||||
<animateMotion path="M 800 -200 L 800 -300 L 800 -200" dur="20s" begin="0s" repeatCount="indefinite" />
|
||||
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 210 530 ; -30 210 530 ; 0 210 530" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite" />
|
||||
</path>
|
||||
|
||||
<circle cx="200" cy="150" r="20" stroke="#1a73e8" fill="#1a73e8">
|
||||
<animateMotion path="M 0 0 L 40 20 Z" dur="5s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
|
||||
<!-- 三角形 -->
|
||||
<path d="M 165 580 L 270 580 Q275 578 270 570 L 223 483 Q220 480 217 483 L 165 570 Q160 578 165 580" stroke="rgb(238, 103, 92)" fill="rgb(238, 103, 92)">
|
||||
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="0 210 530" to="360 210 530" repeatCount="indefinite" />
|
||||
</path>
|
||||
|
||||
<circle cx="1200" cy="600" r="30" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
|
||||
<animateMotion path="M 0 0 L -20 40 Z" dur="9s" repeatCount="indefinite" />
|
||||
</circle>
|
||||
|
||||
<path d="M 100 350 A 40 40 0 1 1 180 350 L 180 430 A 40 40 0 1 1 100 430 Z" stroke="rgb(241, 243, 244)" fill="rgb(241, 243, 244)">
|
||||
<animateMotion path="M 140 390 L 180 360 L 140 390" dur="20s" begin="0s" repeatCount="indefinite" />
|
||||
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="30s" type="rotate" values="0 140 390; -60 140 390; 0 140 390" keyTimes="0 ; 0.5 ; 1" repeatCount="indefinite" />
|
||||
</path>
|
||||
|
||||
<rect x="400" y="600" rx="40" ry="40" width="100" height="100" stroke="rgb(129, 201, 149)" fill="rgb(129, 201, 149)">
|
||||
<animateTransform attributeType="XML" attributeName="transform" begin="0s" dur="35s" type="rotate" from="-30 550 750" to="330 550 750" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
@ -57,24 +57,21 @@ module.exports = (options, ctx) => ({
|
||||
'vuepress-plugin-smooth-scroll',
|
||||
['container', {
|
||||
type: 'tip',
|
||||
defaultTitle: {
|
||||
'/': '',
|
||||
'/zh/': '提示'
|
||||
}
|
||||
before: info => `<div class="custom-block tip"><p class="title">${info}</p>`,
|
||||
after: '</div>',
|
||||
defaultTitle: ''
|
||||
}],
|
||||
['container', {
|
||||
type: 'warning',
|
||||
defaultTitle: {
|
||||
'/': '',
|
||||
'/zh/': '注意'
|
||||
}
|
||||
before: info => `<div class="custom-block warning"><p class="title">${info}</p>`,
|
||||
after: '</div>',
|
||||
defaultTitle: ''
|
||||
}],
|
||||
['container', {
|
||||
type: 'danger',
|
||||
defaultTitle: {
|
||||
'/': '',
|
||||
'/zh/': '警告'
|
||||
}
|
||||
before: info => `<div class="custom-block danger"><p class="title">${info}</p>`,
|
||||
after: '</div>',
|
||||
defaultTitle: ''
|
||||
}],
|
||||
['container', {
|
||||
type: 'right',
|
||||
@ -83,7 +80,8 @@ module.exports = (options, ctx) => ({
|
||||
['container', {
|
||||
type: 'theorem',
|
||||
before: info => `<div class="custom-block theorem"><p class="title">${info}</p>`,
|
||||
after: '</div>'
|
||||
after: '</div>',
|
||||
defaultTitle: ''
|
||||
}],
|
||||
['container', {
|
||||
type: 'details',
|
||||
|
@ -9,6 +9,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance, onMounted } from 'vue-demi'
|
||||
const msgs = [
|
||||
`There's nothing here.`,
|
||||
`How did we get here?`,
|
||||
@ -16,28 +17,32 @@ const msgs = [
|
||||
`Looks like we've got some broken links.`
|
||||
]
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
noFoundPageByTencent () {
|
||||
return this.$themeConfig.noFoundPageByTencent !== false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.noFoundPageByTencent) {
|
||||
const dom = document.createElement('script')
|
||||
dom.setAttribute('homePageName', '回到首页')
|
||||
dom.setAttribute('homePageUrl', '/')
|
||||
dom.setAttribute('src', '//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js')
|
||||
export default defineComponent({
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
document.body.append(dom)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMsg () {
|
||||
const noFoundPageByTencent = computed(() => {
|
||||
return instance.$themeConfig.noFoundPageByTencent !== false
|
||||
})
|
||||
|
||||
const getMsg = () => {
|
||||
return msgs[Math.floor(Math.random() * msgs.length)]
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (noFoundPageByTencent.value) {
|
||||
const dom = document.createElement('script')
|
||||
dom.setAttribute('homePageName', '回到首页')
|
||||
dom.setAttribute('homePageUrl', instance.$site.base)
|
||||
dom.setAttribute('src', '//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js')
|
||||
|
||||
document.body.append(dom)
|
||||
}
|
||||
})
|
||||
|
||||
return { noFoundPageByTencent, getMsg }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
@ -6,7 +6,8 @@
|
||||
<li
|
||||
class="category-item"
|
||||
:class="title == item.name ? 'active': ''"
|
||||
v-for="(item, index) in this.$categories.list"
|
||||
v-for="(item, index) in $categoriesList"
|
||||
v-show="item.pages.length > 0"
|
||||
:key="index">
|
||||
<router-link :to="item.path">
|
||||
<span class="category-name">{{ item.name }}</span>
|
||||
@ -22,90 +23,57 @@
|
||||
v-show="recoShowModule"
|
||||
class="list"
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
@currentTag="getCurrentTag"></note-abstract>
|
||||
</ModuleTransition>
|
||||
|
||||
<!-- 分页 -->
|
||||
<ModuleTransition delay="0.16">
|
||||
<pagation
|
||||
class="pagation"
|
||||
:total="posts.length"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"></pagation>
|
||||
@paginationChange="paginationChange"
|
||||
></note-abstract>
|
||||
</ModuleTransition>
|
||||
</Common>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import Common from '@theme/components/Common'
|
||||
import NoteAbstract from '@theme/components/NoteAbstract'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import pagination from '@theme/mixins/pagination'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import { sortPostsByStickyAndDate, filterPosts } from '@theme/helpers/postData'
|
||||
import { getOneColor } from '@theme/helpers/other'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [pagination, moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { Common, NoteAbstract, ModuleTransition },
|
||||
|
||||
data () {
|
||||
return {
|
||||
currentPage: 1
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
computed: {
|
||||
// 时间降序后的博客列表
|
||||
posts () {
|
||||
let posts = this.$currentCategories.pages
|
||||
const posts = computed(() => {
|
||||
let posts = instance.$currentCategories.pages
|
||||
posts = filterPosts(posts)
|
||||
sortPostsByStickyAndDate(posts)
|
||||
return posts
|
||||
},
|
||||
// 标题只显示分类名称
|
||||
title () {
|
||||
return this.$currentCategories.key
|
||||
})
|
||||
|
||||
const title = computed(() => {
|
||||
return instance.$currentCategories.key
|
||||
})
|
||||
|
||||
const getCurrentTag = (tag) => {
|
||||
ctx.emit('currentTag', tag)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this._setPage(this._getStoragePage())
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 获取当前tag
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
},
|
||||
// 获取当前页码
|
||||
getCurrentPage (page) {
|
||||
this._setPage(page)
|
||||
const paginationChange = (page) => {
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, 0)
|
||||
}, 100)
|
||||
},
|
||||
_setPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
this._setStoragePage(page)
|
||||
},
|
||||
getOneColor
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route () {
|
||||
this._setPage(this._getStoragePage())
|
||||
}
|
||||
|
||||
return { posts, title, getCurrentTag, paginationChange, getOneColor }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
.categories-wrapper
|
||||
max-width: $contentWidth;
|
||||
margin: 0 auto;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Common :sidebarItems="sidebarItems">
|
||||
<Common :sidebarItems="sidebarItems" :showModule="recoShowModule">
|
||||
<component v-if="$frontmatter.home" :is="homeCom"/>
|
||||
<Page v-else :sidebar-items="sidebarItems"/>
|
||||
<Footer v-if="$frontmatter.home" class="footer" />
|
||||
@ -7,33 +7,45 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import Home from '@theme/components/Home'
|
||||
import HomeBlog from '@theme/components/HomeBlog'
|
||||
import Page from '@theme/components/Page'
|
||||
import Footer from '@theme/components/Footer'
|
||||
import Common from '@theme/components/Common'
|
||||
import { resolveSidebarItems } from '@theme/helpers/utils'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { HomeBlog, Home, Page, Common, Footer },
|
||||
computed: {
|
||||
sidebarItems () {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$page.regularPath,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
)
|
||||
},
|
||||
homeCom () {
|
||||
const { type } = this.$themeConfig
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const sidebarItems = computed(() => {
|
||||
if (instance.$page) {
|
||||
return resolveSidebarItems(
|
||||
instance.$page,
|
||||
instance.$page.regularPath,
|
||||
instance.$site,
|
||||
instance.$localePath
|
||||
)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
const homeCom = computed(() => {
|
||||
const { type } = instance.$themeConfig || {}
|
||||
if (type !== undefined) {
|
||||
return type == 'blog' ? 'HomeBlog' : type
|
||||
}
|
||||
return 'Home'
|
||||
}
|
||||
})
|
||||
|
||||
return { sidebarItems, homeCom }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
@ -16,91 +16,61 @@
|
||||
v-show="recoShowModule"
|
||||
class="list"
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
@currentTag="$currentTags.key"></note-abstract>
|
||||
</ModuleTransition>
|
||||
|
||||
<!-- 分页 -->
|
||||
<ModuleTransition delay="0.16">
|
||||
<pagation
|
||||
class="pagation"
|
||||
:total="posts.length"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"></pagation>
|
||||
:currentTag="$currentTags.key"
|
||||
@paginationChange="paginationChange"></note-abstract>
|
||||
</ModuleTransition>
|
||||
</Common>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, getCurrentInstance } from 'vue-demi'
|
||||
import Common from '@theme/components/Common'
|
||||
import NoteAbstract from '@theme/components/NoteAbstract'
|
||||
import TagList from '@theme/components/TagList'
|
||||
import pagination from '@theme/mixins/pagination'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import { sortPostsByStickyAndDate, filterPosts } from '@theme/helpers/postData'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [pagination, moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { Common, NoteAbstract, TagList, ModuleTransition },
|
||||
|
||||
data () {
|
||||
return {
|
||||
currentPage: 1,
|
||||
currentTag: '全部'
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
computed: {
|
||||
// 时间降序后的博客列表
|
||||
posts () {
|
||||
let posts = this.$currentTags.pages
|
||||
const posts = computed(() => {
|
||||
let posts = instance.$currentTags.pages
|
||||
posts = filterPosts(posts)
|
||||
sortPostsByStickyAndDate(posts)
|
||||
return posts
|
||||
})
|
||||
|
||||
const getCurrentTag = (tag) => {
|
||||
ctx.emit('currentTag', tag)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this._setPage(this._getStoragePage())
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 获取当前tag
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
},
|
||||
tagClick (tagInfo) {
|
||||
if (this.$route.path !== tagInfo.path) {
|
||||
this.$router.push({ path: tagInfo.path })
|
||||
const tagClick = (tagInfo) => {
|
||||
if (instance.$route.path !== tagInfo.path) {
|
||||
instance.$router.push({ path: tagInfo.path })
|
||||
}
|
||||
},
|
||||
// 获取当前页码
|
||||
getCurrentPage (page) {
|
||||
this._setPage(page)
|
||||
}
|
||||
|
||||
const paginationChange = (page) => {
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, 0)
|
||||
}, 100)
|
||||
},
|
||||
_setPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
this._setStoragePage(page)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route () {
|
||||
this._setPage(this._getStoragePage())
|
||||
}
|
||||
return { posts, getCurrentTag, tagClick, paginationChange }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/mode.styl'
|
||||
|
||||
.tag-wrapper
|
||||
max-width: $contentWidth;
|
||||
margin: 0 auto;
|
||||
|
@ -4,7 +4,7 @@
|
||||
<ModuleTransition>
|
||||
<TagList
|
||||
v-show="recoShowModule"
|
||||
:currentTag="currentTag"
|
||||
:currentTag="$recoLocales.all"
|
||||
@getCurrentTag="tagClick"></TagList>
|
||||
</ModuleTransition>
|
||||
|
||||
@ -14,77 +14,42 @@
|
||||
v-show="recoShowModule"
|
||||
class="list"
|
||||
:data="$recoPosts"
|
||||
:currentPage="currentPage"
|
||||
:currentTag="currentTag"
|
||||
@currentTag="getCurrentTag"></note-abstract>
|
||||
</ModuleTransition>
|
||||
|
||||
<!-- 分页 -->
|
||||
<ModuleTransition delay="0.16">
|
||||
<pagation
|
||||
class="pagation"
|
||||
:total="$recoPosts.length"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"></pagation>
|
||||
@paginationChange="paginationChange"
|
||||
></note-abstract>
|
||||
</ModuleTransition>
|
||||
</Common>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, getCurrentInstance } from 'vue-demi'
|
||||
import Common from '@theme/components/Common'
|
||||
import TagList from '@theme/components/TagList'
|
||||
import NoteAbstract from '@theme/components/NoteAbstract'
|
||||
import pagination from '@theme/mixins/pagination'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [pagination, moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { Common, NoteAbstract, TagList, ModuleTransition },
|
||||
data () {
|
||||
return {
|
||||
tags: [],
|
||||
currentTag: '全部',
|
||||
currentPage: 1,
|
||||
allTagName: '全部'
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.$tags.list.length > 0) {
|
||||
this.currentTag = this.$route.query.tag ? this.$route.query.tag : this.currentTag
|
||||
}
|
||||
},
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
mounted () {
|
||||
this._setPage(this._getStoragePage())
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
tagClick (tagInfo) {
|
||||
if (this.$route.path !== tagInfo.path) {
|
||||
this.$router.push({ path: tagInfo.path })
|
||||
const tagClick = (tagInfo) => {
|
||||
if (instance.$route.path !== tagInfo.path) {
|
||||
instance.$router.push({ path: tagInfo.path })
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
},
|
||||
|
||||
getCurrentPage (page) {
|
||||
this._setPage(page)
|
||||
const paginationChange = (page) => {
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, 0)
|
||||
}, 100)
|
||||
},
|
||||
_setPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
this._setStoragePage(page)
|
||||
}
|
||||
|
||||
return { tagClick, paginationChange }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Common class="timeline-wrapper" :sidebar="false">
|
||||
<ul class="timeline-content">
|
||||
<ModuleTransition >
|
||||
<li v-show="recoShowModule" class="desc">Yesterday Once More!</li>
|
||||
<li v-show="recoShowModule" class="desc">{{$recoLocales.timeLineMsg}}</li>
|
||||
</ModuleTransition>
|
||||
<ModuleTransition
|
||||
:delay="String(0.08 * (index + 1))"
|
||||
@ -12,7 +12,7 @@
|
||||
<h3 class="year">{{item.year}}</h3>
|
||||
<ul class="year-wrapper">
|
||||
<li v-for="(subItem, subIndex) in item.data" :key="subIndex">
|
||||
<span class="date">{{subItem.frontmatter.date | dateFormat}}</span>
|
||||
<span class="date">{{dateFormat(subItem.frontmatter.date)}}</span>
|
||||
<span class="title" @click="go(subItem.path)">{{subItem.title}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
@ -23,16 +23,23 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, getCurrentInstance } from 'vue-demi'
|
||||
import Common from '@theme/components/Common'
|
||||
import ModuleTransition from '@theme/components/ModuleTransition'
|
||||
import { ModuleTransition } from '@vuepress-reco/core/lib/components'
|
||||
import moduleTransitonMixin from '@theme/mixins/moduleTransiton'
|
||||
|
||||
export default {
|
||||
mixins: [moduleTransitonMixin],
|
||||
export default defineComponent({
|
||||
name: 'TimeLine',
|
||||
mixins: [moduleTransitonMixin],
|
||||
components: { Common, ModuleTransition },
|
||||
filters: {
|
||||
dateFormat (date, type) {
|
||||
setup (props, ctx) {
|
||||
const instance = getCurrentInstance().proxy
|
||||
|
||||
const go = (url) => {
|
||||
instance.$router.push({ path: url })
|
||||
}
|
||||
|
||||
const dateFormat = (date, type) => {
|
||||
function renderTime (date) {
|
||||
const dateee = new Date(date).toJSON()
|
||||
return new Date(+new Date(dateee) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '').replace(/-/g, '/')
|
||||
@ -43,13 +50,10 @@ export default {
|
||||
const day = dateObj.getDate()
|
||||
return `${mon}-${day}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
go (url) {
|
||||
this.$router.push({ path: url })
|
||||
}
|
||||
|
||||
return { go, dateFormat }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
@ -128,7 +132,7 @@ export default {
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: -19px;
|
||||
left: -18px;
|
||||
top: 41px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
|
@ -1,8 +1,9 @@
|
||||
export default {
|
||||
homeBlog: {
|
||||
article: 'Article',
|
||||
tag: 'Tag',
|
||||
category: 'Category',
|
||||
friendLink: 'Friend Link'
|
||||
}
|
||||
all: 'All',
|
||||
article: 'Articles',
|
||||
tag: 'Tags',
|
||||
category: 'Categories',
|
||||
friendLink: 'Friend Links',
|
||||
timeLine: 'TimeLine',
|
||||
timeLineMsg: 'Yesterday Once More!'
|
||||
}
|
||||
|
9
packages/vuepress-theme-reco/locales/es.js
Normal file
9
packages/vuepress-theme-reco/locales/es.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
all: 'Todas',
|
||||
article: 'Artículos',
|
||||
tag: 'Etiquetas',
|
||||
category: 'Categorías',
|
||||
friendLink: 'Páginas amigas',
|
||||
timeLine: 'Cronología',
|
||||
timeLineMsg: '¡Ayer otra vez!'
|
||||
}
|
@ -3,5 +3,6 @@ import zhHant from './zh-hant.js'
|
||||
import en from './en.js'
|
||||
import ja from './ja.js'
|
||||
import ko from './ko.js'
|
||||
import es from './es.js'
|
||||
|
||||
export { zhHans, zhHant, en, ja, ko }
|
||||
export { zhHans, zhHant, en, ja, ko, es }
|
||||
|
@ -1,8 +1,9 @@
|
||||
export default {
|
||||
homeBlog: {
|
||||
article: '文章',
|
||||
tag: 'ラベル',
|
||||
category: '分類',
|
||||
friendLink: '友情リンク'
|
||||
}
|
||||
all: '全部',
|
||||
article: '文章',
|
||||
tag: 'ラベル',
|
||||
category: '分類',
|
||||
friendLink: '友情リンク',
|
||||
timeLine: 'タイムライン',
|
||||
timeLineMsg: '昨日また!'
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
export default {
|
||||
homeBlog: {
|
||||
article: '글',
|
||||
tag: '태그',
|
||||
category: '분류',
|
||||
friendLink: '링크 참조'
|
||||
}
|
||||
all: '전체',
|
||||
article: '글',
|
||||
tag: '태그',
|
||||
category: '분류',
|
||||
friendLink: '링크 참조',
|
||||
timeLine: '타임 라인',
|
||||
timeLineMsg: '어제 또!'
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
export default {
|
||||
homeBlog: {
|
||||
article: '文章',
|
||||
tag: '标签',
|
||||
category: '分类',
|
||||
friendLink: '友情链接'
|
||||
}
|
||||
all: '全部',
|
||||
article: '文章',
|
||||
tag: '标签',
|
||||
category: '分类',
|
||||
friendLink: '友情链接',
|
||||
timeLine: '时间轴',
|
||||
timeLineMsg: '昨日重现!'
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
export default {
|
||||
homeBlog: {
|
||||
article: '文章',
|
||||
tag: '標簽',
|
||||
category: '分類',
|
||||
friendLink: '友情鏈接'
|
||||
}
|
||||
all: '全部',
|
||||
article: '文章',
|
||||
tag: '標簽',
|
||||
category: '分類',
|
||||
friendLink: '友情鏈接',
|
||||
timeLine: '時間軸',
|
||||
timeLineMsg: '昨日重現!'
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
export default {
|
||||
methods: {
|
||||
_tagColor () {
|
||||
const tagColorArr = ['#e15b64', '#f47e60', '#f8b26a', '#abbd81', '#849b87', '#e15b64', '#f47e60', '#f8b26a', '#f26d6d', '#67cc86', '#fb9b5f', '#3498db']
|
||||
const index = Math.floor(Math.random() * tagColorArr.length)
|
||||
return tagColorArr[index]
|
||||
},
|
||||
// 获取当前页码
|
||||
_getStoragePage () {
|
||||
const path = window.location.pathname
|
||||
const currentPage = JSON.parse(sessionStorage.getItem('currentPage'))
|
||||
|
||||
if (currentPage === null || path !== currentPage.path) {
|
||||
sessionStorage.setItem('currentPage', { page: 1, path: '' })
|
||||
return 1
|
||||
}
|
||||
|
||||
return parseInt(currentPage.page)
|
||||
},
|
||||
// 设置当前页码
|
||||
_setStoragePage (page) {
|
||||
const path = window.location.pathname
|
||||
sessionStorage.setItem('currentPage', JSON.stringify({ page, path }))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,26 @@
|
||||
import { zhHans, zhHant, en, ja, ko } from '../locales/index'
|
||||
import { zhHans, zhHant, en, ja, ko, es } from '../locales/index'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
$recoLocales () {
|
||||
const recoLocales = this.$themeLocaleConfig.recoLocales
|
||||
if (recoLocales && recoLocales.homeBlog) {
|
||||
return { homeBlog: recoLocales.homeBlog }
|
||||
}
|
||||
const recoLocales = this.$themeLocaleConfig.recoLocales || {}
|
||||
|
||||
if (/^zh\-(CN|SG)$/.test(this.$lang)) {
|
||||
return zhHans
|
||||
return { ...zhHans, ...recoLocales }
|
||||
}
|
||||
if (/^zh\-(HK|MO|TW)$/.test(this.$lang)) {
|
||||
return zhHant
|
||||
return { ...zhHant, ...recoLocales }
|
||||
}
|
||||
if (/^ja\-JP$/.test(this.$lang)) {
|
||||
return ja
|
||||
return { ...ja, ...recoLocales }
|
||||
}
|
||||
if (/^ko\-KR$/.test(this.$lang)) {
|
||||
return ko
|
||||
return { ...ko, ...recoLocales }
|
||||
}
|
||||
return en
|
||||
if (/^es(\-[A-Z]+)?$/.test(this.$lang)) {
|
||||
return { ...es, ...recoLocales }
|
||||
}
|
||||
return { ...en, ...recoLocales }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,15 @@ export default {
|
||||
mounted () {
|
||||
this.recoShowModule = true
|
||||
},
|
||||
destroyed () {
|
||||
this.recoShowModule = false
|
||||
watch: {
|
||||
'$route' (newV, oldV) {
|
||||
if (newV.path === oldV.path) return
|
||||
|
||||
this.recoShowModule = false
|
||||
|
||||
setTimeout(() => {
|
||||
this.recoShowModule = true
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export default {
|
||||
const currentPage = JSON.parse(sessionStorage.getItem('currentPage'))
|
||||
|
||||
if (currentPage === null || path !== currentPage.path) {
|
||||
sessionStorage.setItem('currentPage', { page: 1, path: '' })
|
||||
sessionStorage.setItem('currentPage', JSON.stringify({ page: 1, path: '' }))
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,7 @@ import { filterPosts, sortPostsByStickyAndDate, sortPostsByDate } from '../helpe
|
||||
export default {
|
||||
computed: {
|
||||
$recoPosts () {
|
||||
const {
|
||||
$categories: { list: articles }
|
||||
} = this
|
||||
|
||||
let posts = articles.reduce((allData, currentData) => {
|
||||
return [...allData, ...currentData.pages]
|
||||
}, [])
|
||||
let posts = this.$site.pages
|
||||
|
||||
posts = filterPosts(posts, false)
|
||||
sortPostsByStickyAndDate(posts)
|
||||
@ -41,6 +35,40 @@ export default {
|
||||
}
|
||||
|
||||
return formatPagesArr
|
||||
},
|
||||
$categoriesList () {
|
||||
return this.$categories.list.map(category => {
|
||||
category.pages = category.pages.filter(page => {
|
||||
return page.frontmatter.publish !== false
|
||||
})
|
||||
return category
|
||||
})
|
||||
},
|
||||
$tagesList () {
|
||||
return this.$tags.list.map(tag => {
|
||||
tag.pages = tag.pages.filter(page => {
|
||||
return page.frontmatter.publish !== false
|
||||
})
|
||||
return tag
|
||||
})
|
||||
},
|
||||
$showSubSideBar () {
|
||||
const {
|
||||
$themeConfig: { subSidebar: themeSubSidebar, sidebar: themeSidebar },
|
||||
$frontmatter: { subSidebar: pageSubSidebar, sidebar: pageSidebar }
|
||||
} = this
|
||||
|
||||
const headers = this.$page.headers || []
|
||||
|
||||
if ([pageSubSidebar, pageSidebar].indexOf(false) > -1) {
|
||||
return false
|
||||
} else if ([pageSubSidebar, pageSidebar].indexOf('auto') > -1 && headers.length > 0) {
|
||||
return true
|
||||
} else if ([themeSubSidebar, themeSidebar].indexOf('auto') > -1 && headers.length > 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user