├── LICENSE ├── README.md ├── _config.yml ├── api ├── auth.ts └── callback.ts ├── lib ├── config.ts └── scopes.ts ├── package.json ├── scaffolds ├── draft.md ├── page.md └── post.md ├── source ├── 404.html ├── _posts │ ├── index.md │ └── publications.md └── admin │ ├── config.yml │ └── index.html ├── themes └── Academia │ ├── LICENSE │ ├── README.md │ ├── _config.yml │ ├── layout │ ├── includes │ │ ├── footer.pug │ │ ├── header.pug │ │ ├── layout.pug │ │ ├── mathjax.pug │ │ ├── mobile-nav.pug │ │ ├── netlify-cms.pug │ │ ├── side-card.pug │ │ └── statistic.pug │ ├── index.pug │ └── page.pug │ ├── scripts │ └── datafile.js │ └── source │ ├── attaches │ └── CV.pdf │ ├── css │ ├── _highlight │ │ └── highlight.styl │ ├── index.styl │ └── user.styl │ ├── img │ ├── favicon.png │ └── profile.png │ └── js │ └── main.js └── vercel.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 HANGVANE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # academia-hexo-netlify-cms-vercel 2 | 3 | A template to deploy your Hexo **Academic Homepage** with Netlify-CMS on Vercel. 4 | 5 | Maybe the easiest way to generate your academic homepage in best practice. 6 | 7 | ✔ Totally free of charge 8 | 9 | ✔ Static web pages, no rendering time 10 | 11 | ✔ Edit online, just as simple as using a dynamic CMS, supported by Netlify-CMS 12 | 13 | ✔ No local environment required, you can edit your pages on any devices, everywhere 14 | 15 | ✔ Zero coding 16 | 17 | ✔ Preview is supported by Netlify-CMS and Netlify 18 | 19 | ✔ Vercel CDN makes your pages to load quickly from anywhere in the world, including China Mainland 20 | 21 | ✔ Easy to bind to your domain, and enable SSL encrypt, supported by Vercel 22 | 23 | ✔ Responsive layout, mobile devices supported by Academia theme 24 | 25 | # Additional improvements 26 | 27 | - Customized 404 page 28 | 29 | - Academia theme bug fixed 30 | 31 | - Permalink format of articles is changed to `https:///title` 32 | 33 | - Provides common pages of academic homepage 34 | 35 | - Unified style of Netlify-CMS preview pane with Academia theme 36 | 37 | - LaTeX formula support added, can be disabled in `themes/Academia/_config.yml` 38 | 39 | - Statistic support added, can be disabled in `themes/Academia/_config.yml` 40 | 41 | # Usage 42 | 43 | Just follow the steps in [hexo-netlify-cms-vercel](https://github.com/hangvane/hexo-netlify-cms-vercel#usage). 44 | 45 | Congratulations! You have successfully deployed your academic homepage in best practice. 46 | 47 | # Thanks 48 | 49 | The oauth gateway for Netlify CMS is implemented by [ublabs/netlify-cms-oauth](https://github.com/ublabs/netlify-cms-oauth). 50 | 51 | The Academia theme of Hexo is implemented by [PhosphorW/hexo-theme-academia](https://github.com/PhosphorW/hexo-theme-academia). 52 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Hexo Configuration 2 | ## Docs: https://hexo.io/docs/configuration.html 3 | ## Source: https://github.com/hexojs/hexo/ 4 | 5 | # Site 6 | title: Hexo 7 | subtitle: '' 8 | description: '' 9 | keywords: 10 | author: John Doe 11 | language: en 12 | timezone: '' 13 | 14 | # URL 15 | ## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project' 16 | url: https://academia-hexo-netlify-cms.vercel.app 17 | permalink: :title/ 18 | permalink_defaults: 19 | pretty_urls: 20 | trailing_index: true # Set to false to remove trailing 'index.html' from permalinks 21 | trailing_html: true # Set to false to remove trailing '.html' from permalinks 22 | 23 | # Directory 24 | source_dir: source 25 | public_dir: public 26 | tag_dir: tags 27 | archive_dir: archives 28 | category_dir: categories 29 | code_dir: downloads/code 30 | i18n_dir: :lang 31 | skip_render: 32 | - admin/** 33 | - 404.html 34 | 35 | # Writing 36 | new_post_name: :title.md # File name of new posts 37 | default_layout: post 38 | titlecase: false # Transform title into titlecase 39 | external_link: 40 | enable: true # Open external links in new tab 41 | field: site # Apply to the whole site 42 | exclude: '' 43 | filename_case: 0 44 | render_drafts: false 45 | post_asset_folder: false 46 | relative_link: false 47 | future: true 48 | highlight: 49 | enable: true 50 | line_number: true 51 | auto_detect: false 52 | tab_replace: '' 53 | wrap: true 54 | hljs: false 55 | prismjs: 56 | enable: false 57 | preprocess: true 58 | line_number: true 59 | tab_replace: '' 60 | 61 | # Home page setting 62 | # path: Root path for your blogs index page. (default = '') 63 | # per_page: Posts displayed per page. (0 = disable pagination) 64 | # order_by: Posts order. (Order by date descending by default) 65 | index_generator: 66 | path: '' 67 | per_page: 10 68 | order_by: -date 69 | 70 | # Category & Tag 71 | default_category: uncategorized 72 | category_map: 73 | tag_map: 74 | 75 | # Metadata elements 76 | ## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta 77 | meta_generator: true 78 | 79 | # Date / Time format 80 | ## Hexo uses Moment.js to parse and display date 81 | ## You can customize the date format as defined in 82 | ## http://momentjs.com/docs/#/displaying/format/ 83 | date_format: YYYY-MM-DD 84 | time_format: HH:mm:ss 85 | ## updated_option supports 'mtime', 'date', 'empty' 86 | updated_option: 'mtime' 87 | 88 | # Pagination 89 | ## Set per_page to 0 to disable pagination 90 | per_page: 10 91 | pagination_dir: page 92 | 93 | # Include / Exclude file(s) 94 | ## include:/exclude: options only apply to the 'source/' folder 95 | include: 96 | exclude: 97 | ignore: 98 | 99 | # Extensions 100 | ## Plugins: https://hexo.io/plugins/ 101 | ## Themes: https://hexo.io/themes/ 102 | theme: Academia 103 | 104 | # Deployment 105 | ## Docs: https://hexo.io/docs/one-command-deployment 106 | deploy: 107 | type: '' 108 | -------------------------------------------------------------------------------- /api/auth.ts: -------------------------------------------------------------------------------- 1 | import { IncomingMessage, ServerResponse } from "http"; 2 | import { AuthorizationCode } from "simple-oauth2"; 3 | import { randomBytes } from "crypto"; 4 | import { config } from "../lib/config"; 5 | import { scopes } from "../lib/scopes"; 6 | 7 | export const randomString = () => randomBytes(4).toString("hex"); 8 | 9 | export default async (req: IncomingMessage, res: ServerResponse) => { 10 | const { host } = req.headers; 11 | const url = new URL(`https://${host}/${req.url}`); 12 | const urlParams = url.searchParams; 13 | const provider = urlParams.get("provider"); 14 | 15 | const client = new AuthorizationCode(config(provider)); 16 | 17 | const authorizationUri = client.authorizeURL({ 18 | redirect_uri: `https://${host}/callback?provider=${provider}`, 19 | scope: scopes[provider], 20 | state: randomString(), 21 | }); 22 | 23 | res.writeHead(301, { Location: authorizationUri }); 24 | res.end(); 25 | }; 26 | -------------------------------------------------------------------------------- /api/callback.ts: -------------------------------------------------------------------------------- 1 | import { IncomingMessage, ServerResponse } from "http"; 2 | import { AuthorizationCode } from "simple-oauth2"; 3 | import { config } from "../lib/config"; 4 | 5 | export default async (req: IncomingMessage, res: ServerResponse) => { 6 | const { host } = req.headers; 7 | const url = new URL(`https://${host}/${req.url}`); 8 | const urlParams = url.searchParams; 9 | const code = urlParams.get("code"); 10 | const provider = urlParams.get("provider"); 11 | const client = new AuthorizationCode(config(provider)); 12 | const tokenParams = { 13 | code, 14 | redirect_uri: `https://${host}/callback?provider=${provider}`, 15 | }; 16 | 17 | try { 18 | const accessToken = await client.getToken(tokenParams); 19 | const token = accessToken.token["access_token"]; 20 | 21 | const responseBody = renderBody("success", { 22 | token, 23 | provider, 24 | }); 25 | 26 | res.statusCode = 200; 27 | res.end(responseBody); 28 | } catch (e) { 29 | res.statusCode = 200; 30 | res.end(renderBody("error", e)); 31 | } 32 | }; 33 | 34 | function renderBody( 35 | status: string, 36 | content: { 37 | token: string; 38 | provider: string; 39 | } 40 | ) { 41 | return ` 42 | 57 | `; 58 | } 59 | -------------------------------------------------------------------------------- /lib/config.ts: -------------------------------------------------------------------------------- 1 | export const config = (provider: string) => ({ 2 | client: { 3 | id: client[provider].id, 4 | secret: client[provider].secret, 5 | }, 6 | auth: { 7 | tokenHost: auth[provider].tokenHost, 8 | tokenPath: auth[provider].tokenPath, 9 | authorizePath: auth[provider].authorizePath, 10 | }, 11 | }); 12 | 13 | const auth = { 14 | github: { 15 | tokenHost: "https://github.com", 16 | tokenPath: "/login/oauth/access_token", 17 | authorizePath: "/login/oauth/authorize", 18 | }, 19 | gitlab: { 20 | tokenHost: "https://gitlab.com", 21 | tokenPath: "/oauth/token", 22 | authorizePath: "/oauth/authorize", 23 | }, 24 | }; 25 | 26 | const client = { 27 | github: { 28 | id: process.env.OAUTH_GITHUB_CLIENT_ID, 29 | secret: process.env.OAUTH_GITHUB_CLIENT_SECRET, 30 | }, 31 | gitlab: { 32 | id: process.env.OAUTH_GITLAB_CLIENT_ID, 33 | secret: process.env.OAUTH_GITLAB_CLIENT_SECRET, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /lib/scopes.ts: -------------------------------------------------------------------------------- 1 | export const scopes = { 2 | github: "repo,user", 3 | gitlab: "api", 4 | }; 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-site", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "hexo generate", 7 | "clean": "hexo clean", 8 | "deploy": "hexo deploy", 9 | "server": "hexo server" 10 | }, 11 | "hexo": { 12 | "version": "" 13 | }, 14 | "dependencies": { 15 | "hexo": "^5.0.0", 16 | "hexo-generator-archive": "^1.0.0", 17 | "hexo-generator-category": "^1.0.0", 18 | "hexo-generator-index": "^2.0.0", 19 | "hexo-generator-tag": "^1.0.0", 20 | "hexo-renderer-ejs": "^1.0.0", 21 | "hexo-renderer-marked": "^4.0.0", 22 | "hexo-renderer-stylus": "^2.0.0", 23 | "hexo-renderer-pug": "^1.0.0", 24 | "hexo-server": "^2.0.0", 25 | "simple-oauth2": "^4.2.0" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^14.14.25", 29 | "@types/simple-oauth2": "^4.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scaffolds/draft.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: {{ title }} 3 | tags: 4 | --- 5 | -------------------------------------------------------------------------------- /scaffolds/page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: {{ title }} 3 | date: {{ date }} 4 | --- 5 | -------------------------------------------------------------------------------- /scaffolds/post.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: {{ title }} 3 | date: {{ date }} 4 | tags: 5 | --- 6 | -------------------------------------------------------------------------------- /source/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 404 Not Found 7 | 34 | 35 | 36 |
37 |
38 |
404
39 | > > Go back to the homepage > > 40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /source/_posts/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Index 3 | academia: true 4 | --- 5 | 6 | # academia-hexo-netlify-cms-vercel 7 | 8 | A template to deploy your Hexo **Academic Homepage** with Netlify-CMS on Vercel. 9 | 10 | Maybe the easiest way to generate your academic homepage in best practice. 11 | 12 | ✔ Totally free of charge 13 | 14 | ✔ Static web pages, no rendering time 15 | 16 | ✔ Edit online, just as simple as using a dynamic CMS, supported by Netlify-CMS 17 | 18 | ✔ No local environment required, you can edit your pages on any devices, everywhere 19 | 20 | ✔ Zero coding 21 | 22 | ✔ Preview is supported by Netlify-CMS and Netlify 23 | 24 | ✔ Vercel CDN makes your pages to load quickly from anywhere in the world, including China Mainland 25 | 26 | ✔ Easy to bind to your domain, and enable SSL encrypt, supported by Vercel 27 | 28 | ✔ Responsive layout, mobile devices supported by Academia theme 29 | 30 | # Additional improvements 31 | 32 | - Customized 404 page 33 | 34 | - Academia theme bug fixed 35 | 36 | - Unified style of Netlify-CMS preview pane with Academia theme 37 | 38 | - Permalink format of articles is changed to `https:///title` 39 | 40 | - Provides common pages of academic homepage 41 | 42 | - $\LaTeX$ formula support added, can be disabled in `themes/Academia/_config.yml` 43 | 44 | - Statistic support added, can be disabled in `themes/Academia/_config.yml` 45 | 46 | # Usage 47 | 48 | Just follow the steps in [hexo-netlify-cms-vercel](https://github.com/hangvane/hexo-netlify-cms-vercel#usage). 49 | 50 | Congratulations! You have successfully deployed your academic homepage in best practice. 51 | 52 | # Thanks 53 | 54 | The oauth gateway for Netlify CMS is implemented by [ublabs/netlify-cms-oauth](https://github.com/ublabs/netlify-cms-oauth). 55 | 56 | The Academia theme of Hexo is implemented by [PhosphorW/hexo-theme-academia](https://github.com/PhosphorW/hexo-theme-academia). 57 | -------------------------------------------------------------------------------- /source/_posts/publications.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Publications 3 | --- 4 | 5 | This is test content2. 6 | 7 | $$ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} $$ 8 | $$ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha} $$ 9 | -------------------------------------------------------------------------------- /source/admin/config.yml: -------------------------------------------------------------------------------- 1 | backend: 2 | name: github 3 | repo: hangvane/academia-hexo-netlify-cms-vercel # Path to your Github/Gitlab repository 4 | branch: main # Branch to update 5 | base_url: https://academia-hexo-netlify-cms.vercel.app 6 | 7 | # These lines should *not* be indented 8 | media_folder: 'source/images' # Media files will be stored in the repo under source/images 9 | public_folder: 'images' # The src attribute for uploaded media will begin with images 10 | 11 | # This line should *not* be indented 12 | publish_mode: editorial_workflow 13 | 14 | collections: 15 | - name: 'Page' # Used in routes, e.g., /admin/collections/blog 16 | label: 'Page' # Used in the UI 17 | folder: 'source/_posts' # The path to the folder where the documents are stored 18 | create: true # Allow users to create new documents in this collection 19 | slug: '{{slug}}' # Filename template, e.g., YYYY-MM-DD-title.md 20 | fields: # The fields for each document, usually in front matter 21 | - {label: 'Title', name: 'title', widget: 'string'} 22 | - {label: 'Homepage', name: 'academia', widget: 'boolean', required: false, hint: 'This field determines whether this post is displayed on the homepage.'} 23 | - {label: 'Body', name: 'body', widget: 'markdown'} 24 | -------------------------------------------------------------------------------- /source/admin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Content Manager 8 | 9 | 10 | 11 | 12 | 13 | 26 | 27 | -------------------------------------------------------------------------------- /themes/Academia/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Phower 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /themes/Academia/README.md: -------------------------------------------------------------------------------- 1 | # hexo-theme-academia 2 | 3 | 4 | 5 | Simple page for academic websites on Hexo, crafted from Jekyll/academicpages. 6 | 7 | ## Introduction 8 | This is a light & simple & responsive theme for academic websites on Hexo, crafted from [academicpages](https://github.com/academicpages/academicpages.github.io) on Jekyll. Thanks a lot. 9 | 10 | The theme adopts only `post` and `page` in Hexo to show your informations. For an academic page, it's important to be simple and obvious. 11 | 12 | Example page: [phosphorw.github.io](https://phosphorw.github.io/) 13 | 14 | ![mockup](https://raw.githubusercontent.com/PhosphorW/phower-img-folder/master/hexo-theme-academia_mockup.jpg) 15 | 16 | ## Preparation 17 | 18 | Some skills you need: 19 | - Publish a Hexo blog: [Learn more](https://hexo.io) 20 | - Git 21 | - Markdown: [Learn more](https://www.appinn.com/markdown/#list) 22 | - Deploy a server (Optional) 23 | - Balabala... 24 | 25 | ## Installation 26 | 27 | The simplest way to install is to clone the entire repository: 28 | ``` 29 | git clone https://github.com/PhosphorW/hexo-theme-academia.git themes/Academia 30 | ``` 31 | 32 | Some required renderers: 33 | ``` 34 | npm install hexo-renderer-pug hexo-renderer-stylus --save 35 | ``` 36 | 37 | Set theme in hexo work folder's `_config.yml` 38 | ``` 39 | theme: Academia 40 | ``` 41 | 42 | ## Create your academic page 43 | 44 | Only `post` and `page` are supported in this theme. 45 | 46 | ``` 47 | hexo n post "any title" 48 | ``` 49 | or 50 | ``` 51 | hexo n page "any title" 52 | ``` 53 | 54 | **Important:**
55 | Add `academia: true` in front_matter filed in `post .md`. 56 | 57 | front_matter 58 | 59 | Only post with `academia: true` front_matter will be shown on home (index) page. You can write your informations in either one post or some posts with this method. The front_matter doesn't works in `page`. The `pages` are standalone with its markdown content. 60 | 61 | 62 | ## Theme Configurtion 63 | All of below options can be config in theme folder `_config.yml` 64 | 65 | - Top Menu: in-page anchor, new page links or any links you like 66 | - Side Bar: Support avatar, social links, extra social links (optional), CV_download_link 67 | - Box-shadow mode (optional) 68 | 69 | All icons in page is supported with [font-awesome-5](https://fontawesome.com/) (~~font-awesome-4~~) 70 | 71 | > fontawesome-4 is not used since v1.2.1. If you want to update manually, first change CDN stylesheet to fa5. Then change your previous icon class `fa` to `fas` or `fas`. 72 | 73 | If you need rss feed, use hexo plugin: [hexo-generator-feed](https://github.com/hexojs/hexo-generator-feed) 74 | 75 | ![theme-layout](https://raw.githubusercontent.com/PhosphorW/phower-img-folder/master/hexo-theme-academia_layout.png) 76 | 77 | ### Update Theme 78 | This theme supports `data files` smooth update. Copy `_config.yml` in theme folder to site folder `/source/_data/theme.yml`, if there is no `_data` folder, create it. 79 | 80 | Then you can modify your theme configuration in the mentioned `theme.yml`. If there is any update, just pull the new branch and your configurations won't be merged. 81 | 82 | **Note:** 83 | 1. When use `data files` to config theme, you must restart hexo server after any modifictions. `hexo server` again. 84 | 2. Sometimes there will be changes in theme `_config.yml`, please refer to [release page](https://github.com/PhosphorW/hexo-theme-academia/releases) for more details before update. 85 | 86 | ## Document 87 | 中文文档:[Hexo-Theme-Academia 说明文档](https://phower.me/2020/03/Hexo-theme-academia-%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3/) 88 | 89 | ## Q&A 90 | 91 | - **Some special url links?** 92 | 1. QQ: `tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=[your number]` 93 | 2. E-mail: `mailto:[your email]` 94 | 3. rss: `atom.xml` (need additional hexo plugin to generate XML file) 95 | 96 | ## Changelogs 97 | 98 | 🚀[Release page](https://github.com/PhosphorW/hexo-theme-academia/releases) 99 | 100 | - **v1.2.1**: some small improvements. 101 | - **v1.2.0**: support pjax and data files. -------------------------------------------------------------------------------- /themes/Academia/_config.yml: -------------------------------------------------------------------------------- 1 | favicon: /img/favicon.png 2 | # Change to your profile picture 3 | avatar: /img/avatar.jpg 4 | # if author sets in hexo_config, this string doesn't work 5 | author: 'Jason' 6 | author_bio: 'Your biography can be writed down here.' 7 | 8 | since: 2020 9 | 10 | # Top Menu 顶部菜单 11 | # #title 为页内跳转,单页模式 12 | # 可以选择外链或其他页面 13 | menu: 14 | Publications: /publications 15 | 16 | # flink picture will load if avator link calls on error 17 | loading_bg: 18 | flink: /img/profile.png 19 | 20 | # Social Links; 社交链接,不需要的链接直接注释掉 21 | # 可以调整显示顺序 22 | # 图标调用 font-awesome 4.7 23 | social: 24 | enable: true 25 | social_links: 26 | fab fa-twitter: / 27 | fab fa-facebook-square: / 28 | fab fa-github: / 29 | fab fa-stack-overflow: / 30 | fab fa-linkedin: / 31 | fab fa-weibo: / 32 | fab fa-weixin: / 33 | fab fa-qq: / 34 | fas fa-envelope: / #E-mail 35 | fas fa-rss: / #rss 36 | 37 | # Additional social_links,额外添加自定义链接,可显示链接名称 38 | # name: url || icon_name 39 | e_social: 40 | enable: true 41 | e_social_links: 42 | Google Scholar: / || fas fa-graduation-cap 43 | ORCID: / || fab fa-orcid 44 | 45 | # CV download link 46 | cv_dl: 47 | enable: true 48 | dir: /attaches/CV.pdf 49 | description: My Detail CV. 50 | 51 | # Box-shadow 52 | # display box-shadow on page or not 53 | box_shadow: 54 | enable: false 55 | 56 | # CDN 57 | # 根据需要自行添加js/css 58 | # 自定义css可以直接写在user.styl中 59 | CDN_USE: 60 | css: 61 | - /css/index.css 62 | # - https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css 63 | - https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css # fontawesome 5 64 | js: 65 | - https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js #/js/third-party/jquery.min.js 66 | - https://cdn.jsdelivr.net/npm/jquery-pjax@latest/jquery.pjax.min.js 67 | - /js/main.js 68 | 69 | # MathJax Support 70 | mathjax: 71 | enable: true 72 | cdn: https://cdn.jsdelivr.net/npm/mathjax@2.7.8/MathJax.js?config=TeX-MML-AM_CHTML 73 | 74 | statistic: 75 | enable: true 76 | cdn: https://cdn.jsdelivr.net/gh/xaoxuu/cdn-busuanzi@2.3/js/busuanzi.pure.mini.js 77 | -------------------------------------------------------------------------------- /themes/Academia/layout/includes/footer.pug: -------------------------------------------------------------------------------- 1 | .footer_wrap 2 | if theme.statistic.enable 3 | include ./statistic.pug 4 | - var now = new Date() 5 | - var nowYear = now.getFullYear() 6 | if theme.since && theme.since != nowYear 7 | .copyright!= `©${theme.since} - ${nowYear} by ${config.author}` 8 | else 9 | .copyright!= `©${nowYear} by ${config.author}` 10 | .theme-info Powered by #[a(href='https://hexo.io' rel='nofollow') Hexo] & #[a(href='https://github.com/PhosphorW/hexo-theme-academia' rel='nofollow') Academia Theme] 11 | -------------------------------------------------------------------------------- /themes/Academia/layout/includes/header.pug: -------------------------------------------------------------------------------- 1 | .header_wrap 2 | #blog_name 3 | a#site-name.blog_title(href=url_for('/')) #[=config.title] 4 | button.menus_icon 5 | .navicon 6 | ul.menus_items 7 | each value, label in theme.menu 8 | if !Array.isArray(value) 9 | li.menus_item 10 | a.site-page(href=url_for(trim(value.split('||')[0])))=' ' + label 11 | else 12 | li.menus_item 13 | a.site-page=' ' + trim(label.split('||')[0]) -------------------------------------------------------------------------------- /themes/Academia/layout/includes/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang=config.language) 3 | head 4 | meta(charset='UTF-8') 5 | meta(http-equiv="X-UA-Compatible" content="IE=edge") 6 | meta(name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5") 7 | title=config.title 8 | meta(name="author" content=config.author) 9 | !=favicon_tag(config.favicon || theme.favicon || '/favicon.ico') 10 | each item in theme.CDN_USE.css 11 | link(rel='stylesheet', href=url_for(item)) 12 | body 13 | header#page_header 14 | include ./header.pug 15 | main#page_main 16 | include ./side-card.pug 17 | block content 18 | include ./mobile-nav.pug 19 | footer#page_footer 20 | include ./footer.pug 21 | each item in theme.CDN_USE.js 22 | script(src=url_for(item)) 23 | if theme.mathjax.enable 24 | include ./mathjax.pug 25 | //- include ./netlify-cms.pug 26 | -------------------------------------------------------------------------------- /themes/Academia/layout/includes/mathjax.pug: -------------------------------------------------------------------------------- 1 | script(type='text/x-mathjax-config'). 2 | MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}}); 3 | 4 | script(type='text/javascript', src=theme.mathjax.cdn, async) 5 | 6 | script(type='text/javascript', async). 7 | $(document).on({ 8 | 'pjax:complete': function() { 9 | $.ajax({ 10 | type: "GET", 11 | url: "#{theme.mathjax.cdn}", 12 | dataType: "script", 13 | cache: true, 14 | success: function() { 15 | MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}}); 16 | var math = document.getElementsByClassName("entry-content")[0]; 17 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,math]); 18 | }, 19 | }); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /themes/Academia/layout/includes/mobile-nav.pug: -------------------------------------------------------------------------------- 1 | .nav-wrap 2 | .nav 3 | button.site-nav 4 | .navicon 5 | ul.nav_items 6 | each value, label in theme.menu 7 | if !Array.isArray(value) 8 | li.nav_item 9 | a.nav-page(href=url_for(trim(value.split('||')[0])))=' ' + label 10 | else 11 | li.nav_item 12 | a.nav-page=' ' + trim(label.split('||')[0]) 13 | .cd-top 14 | i(class="fa fa-arrow-up" aria-hidden="true") -------------------------------------------------------------------------------- /themes/Academia/layout/includes/netlify-cms.pug: -------------------------------------------------------------------------------- 1 | script(type='text/javascript', async). 2 | if (window.netlifyIdentity) { 3 | window.netlifyIdentity.on("init", user => { 4 | if (!user) { 5 | window.netlifyIdentity.on("login", () => { 6 | document.location.href = "/admin/"; 7 | }); 8 | } 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /themes/Academia/layout/includes/side-card.pug: -------------------------------------------------------------------------------- 1 | .side-card.sticky 2 | .card-wrap(itemscope itemtype='http://schema.org/Person') 3 | .author-avatar 4 | img.avatar-img(src=url_for(theme.avatar) onerror=`this.onerror=null;this.src='` + url_for(theme.loading_bg.flink) + `'` alt="avatar") 5 | .author-discrip 6 | h3= config.author || theme.author 7 | p.author-bio= theme.author_bio 8 | .author-links 9 | button.btn.m-social-links Links 10 | if(theme.social.enable) 11 | ul.social-icons 12 | each url, icon in theme.social_links 13 | li 14 | a.social-icon(href=url target="_blank") 15 | i(class=icon aria-hidden="true") 16 | if(theme.e_social.enable) 17 | ul.social-links 18 | each value, name in theme.e_social_links 19 | li 20 | a.e-social-link(href=url_for(trim(value.split('||')[0])) target="_blank") 21 | i(class=trim(value.split('||')[1]) aria-hidden="true") 22 | span= name 23 | if(theme.cv_dl.enable) 24 | a.cv-links(href=url_for(theme.cv_dl.dir) target="_blank") 25 | i(class="fas fa-file-pdf" aria-hidden="true") 26 | span= theme.cv_dl.description -------------------------------------------------------------------------------- /themes/Academia/layout/includes/statistic.pug: -------------------------------------------------------------------------------- 1 | script(type='text/javascript', src=theme.statistic.cdn, async) 2 | 3 | span(id='busuanzi_container_site_pv') Hits: 4 | span(id='busuanzi_value_site_pv') 5 | i(class='fa fa-spinner fa-spin') 6 | -------------------------------------------------------------------------------- /themes/Academia/layout/index.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout 2 | 3 | block content 4 | .page(itemscope itemtype='http://schema.org/CreativeWork') 5 | each article in page.posts.data 6 | if article.academia 7 | article!= article.content 8 | -------------------------------------------------------------------------------- /themes/Academia/layout/page.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout 2 | 3 | block content 4 | .page(itemscope itemtype='http://schema.org/CreativeWork') 5 | h2.page-title!= page.title 6 | article!= page.content 7 | -------------------------------------------------------------------------------- /themes/Academia/scripts/datafile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Note: configs in _data/theme.yml will replace configs in hexo.theme.config. 3 | */ 4 | 5 | hexo.on('generateBefore', function () { 6 | if (hexo.locals.get) { 7 | var data = hexo.locals.get('data') // 获取_data文件夹下的内容 8 | data && data.theme && (hexo.theme.config = data.theme) // 如果theme.yml 存在,就把内容替换掉主题的config 9 | } 10 | }) -------------------------------------------------------------------------------- /themes/Academia/source/attaches/CV.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hangvane/academia-hexo-netlify-cms-vercel/ba85629d4292d3df792a5860c9c52a5e83595e6d/themes/Academia/source/attaches/CV.pdf -------------------------------------------------------------------------------- /themes/Academia/source/css/_highlight/highlight.styl: -------------------------------------------------------------------------------- 1 | $code-font-size = 1.6rem 2 | 3 | $highlight-background = lighten(#f2f2f2, 50%) 4 | $highlight-current-line = #00346e 5 | $highlight-selection = #80CBC440 6 | $highlight-foreground = lighten(#333, 15%) 7 | $highlight-comment = #90A4AE90 8 | $highlight-red = #E53935 9 | $highlight-orange = #F76D47 10 | $highlight-yellow = #FFB62C 11 | $highlight-green = #0086b3 12 | $highlight-aqua = #c62641 13 | $highlight-blue = #6182B8 14 | $highlight-purple = #7C4DFF 15 | $highlight-gutter = { 16 | color: #CFD8DC, 17 | bg-color: $highlight-background 18 | } 19 | $highlight-deletion = #fdd 20 | $highlight-addition = #dfd 21 | 22 | $code-block 23 | overflow: auto 24 | margin: 0 0 1rem 25 | padding: 0 26 | background: $highlight-background 27 | color: $highlight-foreground 28 | font-size: $code-font-size 29 | clear both 30 | 31 | figure.highlight 32 | position: relative 33 | 34 | .page 35 | .highlight code 36 | padding: .2rem .3rem 37 | word-wrap: break-word 38 | font-size: $code-font-size !important 39 | 40 | pre 41 | @extend $code-block 42 | padding: 10px 20px 43 | 44 | code 45 | padding: 0 46 | background: none 47 | color: $highlight-foreground 48 | text-shadow: none 49 | 50 | .highlight 51 | @extend $code-block 52 | position: relative 53 | border-radius: 1px 54 | 55 | if hexo-config('highlight_shrink') == true 56 | display: none 57 | 58 | pre 59 | margin: 0 60 | padding: 8px 0 61 | border: none 62 | 63 | .line 64 | &::selection 65 | background: $highlight-selection 66 | color: $highlight-foreground 67 | 68 | &.marked 69 | background-color: $highlight-selection 70 | 71 | table 72 | position: relative 73 | margin: 0 74 | width: auto 75 | border: none 76 | 77 | td 78 | padding: 0 79 | border: none 80 | 81 | .gutter pre 82 | padding-right: .8rem 83 | padding-left: .7rem 84 | background-color: $highlight-gutter.bg-color 85 | color: $highlight-gutter.color 86 | text-align: right 87 | 88 | .code pre 89 | padding-right: .5rem 90 | padding-left: .5rem 91 | width: 100% 92 | background-color: $highlight-background 93 | 94 | .line 95 | height: 1rem 96 | 97 | .gutter 98 | user-select: none 99 | -webkit-user-select: none 100 | -moz-user-select: none 101 | -ms-user-select: none 102 | 103 | .gist table 104 | width: auto 105 | 106 | td 107 | border: none 108 | 109 | // For diff highlight 110 | pre .deletion 111 | background: $highlight-deletion 112 | 113 | pre .addition 114 | background: $highlight-addition 115 | 116 | pre .meta 117 | color: $highlight-purple 118 | 119 | pre 120 | .comment 121 | color: $highlight-comment 122 | 123 | &::selection 124 | background: $highlight-selection 125 | color: $highlight-foreground 126 | 127 | .variable, 128 | .attribute, 129 | .regexp, 130 | .ruby .constant, 131 | .xml .tag .title, 132 | .xml .pi, 133 | .xml .doctype, 134 | .html .doctype, 135 | .css .id, 136 | .tag .name, 137 | .css .class, 138 | .css .pseudo 139 | color: $highlight-red 140 | 141 | &::selection 142 | background: $highlight-selection 143 | color: $highlight-foreground 144 | 145 | .tag 146 | color: $highlight-aqua 147 | 148 | &::selection 149 | background: $highlight-selection 150 | color: $highlight-foreground 151 | 152 | .number, 153 | .preprocessor, 154 | .literal, 155 | .params, 156 | .constant, 157 | .command 158 | color: $highlight-orange 159 | 160 | &::selection 161 | background: $highlight-selection 162 | color: $highlight-foreground 163 | 164 | .built_in 165 | color: $highlight-yellow 166 | 167 | &::selection 168 | background: $highlight-selection 169 | color: $highlight-foreground 170 | 171 | .ruby .class .title, 172 | .css .rules .attribute, 173 | .string, 174 | .value, 175 | .inheritance, 176 | .header, 177 | .ruby .symbol, 178 | .xml .cdata, 179 | .special, 180 | .number, 181 | .formula 182 | color: $highlight-green 183 | 184 | &::selection 185 | background: $highlight-selection 186 | color: $highlight-foreground 187 | 188 | .keyword, 189 | .title, 190 | .css .hexcolor 191 | color: $highlight-aqua 192 | 193 | &::selection 194 | background: $highlight-selection 195 | color: $highlight-foreground 196 | 197 | .function, 198 | .python .decorator, 199 | .python .title, 200 | .ruby .function .title, 201 | .ruby .title .keyword, 202 | .perl .sub, 203 | .javascript .title, 204 | .coffeescript .title 205 | color: $highlight-blue 206 | 207 | &::selection 208 | background: $highlight-selection 209 | color: $highlight-foreground 210 | 211 | .tag .attr, 212 | .javascript .function 213 | color: $highlight-purple 214 | 215 | &::selection 216 | background: $highlight-selection 217 | color: $highlight-foreground -------------------------------------------------------------------------------- /themes/Academia/source/css/index.styl: -------------------------------------------------------------------------------- 1 | @import 'user' 2 | @import '_highlight/highlight.styl' 3 | 4 | $font-family = "Times New Roman", FangSong, STFangsong, sans-serif; 5 | $theme-blue = #1353d7; 6 | $theme-dark-blue = #096494; 7 | $theme-red = #c62641; 8 | 9 | * 10 | -webkit-text-size-adjust: none; 11 | 12 | html 13 | height: 100% 14 | margin 0 15 | font-size: 62.5%; 16 | -webkit-font-smoothing: antialiased; 17 | box-sizing: border-box; 18 | 19 | body 20 | height 100% 21 | margin: 0; 22 | padding: 0; 23 | color: #494e52; 24 | font-size: 1.8em; 25 | line-height: 1.5; 26 | font-family: $font-family 27 | scroll-behavior smooth 28 | 29 | a, 30 | span, 31 | .btn 32 | font-family: $font-family 33 | 34 | img 35 | max-width 100% 36 | 37 | blockquote 38 | position: relative; 39 | color: #999; 40 | font-weight: 400; 41 | background-color #f7f7f7 42 | border-left: 5px solid #777; 43 | padding: 1rem 1rem 1rem 1.5rem; 44 | margin: 1rem 3rem 1rem 2rem; 45 | p 46 | margin 0 47 | 48 | // top menu 49 | //------------------------------------------------ 50 | #page_header 51 | position: relative; 52 | border-bottom: 1px solid #f2f3f3; 53 | -webkit-animation: intro 0.3s both; 54 | animation: intro 0.3s both; 55 | -webkit-animation-delay: 0.15s; 56 | animation-delay: 0.15s; 57 | z-index: 20; 58 | 59 | .header_wrap 60 | max-width: 1200px; 61 | margin-left: auto; 62 | margin-right: auto; 63 | clear: both; 64 | padding: 1.6rem 2rem 1rem; 65 | font-size: 2rem; 66 | 67 | #blog_name 68 | display inline-block 69 | width auto 70 | vertical-align top 71 | 72 | a 73 | display: block; 74 | margin: 0 1.6rem; 75 | padding: 0.8rem 0; 76 | color: #7a8288; 77 | font-weight: 600; 78 | text-decoration: none; 79 | -webkit-transition: all 0.2s ease-in-out; 80 | transition: all 0.2s ease-in-out; 81 | &:hover 82 | color: black; 83 | 84 | @media (max-width: 34em) 85 | .menus-open .menus_items 86 | visibility visible 87 | opacity 1 88 | pointer-events auto 89 | 90 | .menus_items 91 | visibility hidden 92 | opacity 0 93 | position: absolute; 94 | right: 10px; 95 | margin: 0; 96 | box-shadow: rgba(0,0,0,0.25) 0px 0px 10px; 97 | padding: 5px; 98 | border-width: 1px; 99 | border-style: solid; 100 | border-color: #f2f3f3; 101 | border-image: initial; 102 | border-radius: 4px; 103 | background: #fff; 104 | list-style: none; 105 | transition: all ease-in-out 0.2s; 106 | pointer-events none 107 | &::before 108 | display: block; 109 | content: ""; 110 | position: absolute; 111 | top: -10px; 112 | left: calc(50% + 15px); 113 | width: 0px; 114 | z-index: 0; 115 | border-style: solid; 116 | border-width: 0px 10px 10px; 117 | border-color: white transparent; 118 | li 119 | display: block; 120 | border-bottom: 1px solid #f2f3f3; 121 | a 122 | display: block; 123 | color: #7a8288; 124 | font-size: 1.6rem; 125 | margin: 0px; 126 | padding: 8px 15px; 127 | text-decoration: none; 128 | transition: all 0.2s ease-in-out 0s; 129 | 130 | .menus_icon 131 | display inline-block 132 | position: absolute; 133 | right: 30px; 134 | top: 22px; 135 | height: 30px; 136 | width: 30px; 137 | background-color: #7a8288; 138 | color: #fff; 139 | cursor: pointer; 140 | padding: 0px 0.3rem; 141 | border-width: 0px; 142 | outline: none 143 | 144 | .menus-open .navicon 145 | background: transparent; 146 | &::before 147 | transform-origin: 50% 50%; 148 | top: 0px; 149 | left: -3px; 150 | width: 25px; 151 | transform: rotate3d(0, 0, 1, 45deg); 152 | &::after 153 | transform-origin: 50% 50%; 154 | top: 0px; 155 | left: -3px; 156 | width: 25px; 157 | transform: rotate3d(0, 0, 1, -45deg); 158 | 159 | @media (min-width: 34em) 160 | .menus_items 161 | display inline-block 162 | list-style-type none 163 | margin 0 164 | clear both 165 | li 166 | display table-cell 167 | vertical-align middle 168 | a 169 | position: relative; 170 | display: block; 171 | margin: 0 1.6rem; 172 | padding: 0.8rem 0; 173 | color: #7a8288; 174 | text-decoration: none; 175 | &::before 176 | content: ""; 177 | position: absolute; 178 | left: 0; 179 | bottom: 0; 180 | height: 4px; 181 | background: #bdc1c4; 182 | width: 100%; 183 | -webkit-transition: all 0.2s ease-in-out; 184 | transition: all 0.2s ease-in-out; 185 | -webkit-transform: scaleX(0); 186 | -ms-transform: scaleX(0); 187 | transform: scaleX(0); 188 | &:hover 189 | color: #5c6266; 190 | &::before 191 | -webkit-transform: scaleX(1); 192 | -ms-transform: scaleX(1); 193 | transform: scaleX(1); 194 | 195 | .menus_icon 196 | display none 197 | 198 | 199 | // page main 200 | //------------------------------------------------ 201 | #page_main 202 | min-height: 72%; 203 | margin-left: auto; 204 | margin-right: auto; 205 | clear: both; 206 | margin-top: 3.2rem; 207 | margin-bottom: 6.4rem; 208 | padding-left: 1.6rem; 209 | padding-right: 1.6rem; 210 | animation: intro 0.3s both; 211 | animation-delay: 0.35s; 212 | &::after 213 | clear: both; 214 | content: ""; 215 | display: table; 216 | 217 | .page-title 218 | font-size 3rem 219 | padding 0 1.2rem 220 | 221 | .page article 222 | padding-left 1.2rem 223 | padding-right 1.2rem 224 | 225 | h1 226 | font-size 3rem 227 | h2 228 | font-size 2.8rem 229 | h3 230 | font-size 2.6rem 231 | p, 232 | li 233 | font-size 1.8rem 234 | a 235 | color #494e52 236 | -webkit-transition: all 0.2s ease-in-out; 237 | transition: all 0.2s ease-in-out; 238 | &:hover 239 | color: $theme-red; 240 | 241 | .highlight 242 | overflow: auto; 243 | margin: 0 0 1rem; 244 | padding: 0; 245 | background: #f8f8f8; 246 | color: #525252; 247 | line-height: 20px; 248 | 249 | .gutter pre 250 | padding-right: 0.8rem; 251 | padding-left: 0.7rem; 252 | background-color: #f8f8f8; 253 | color: #cfd8dc; 254 | text-align: right; 255 | 256 | code 257 | font-family $font-family 258 | padding: 0.2rem 0.3rem; 259 | background: rgba(27,31,35,0.05); 260 | word-wrap: break-word; 261 | 262 | @media screen and (min-width: 66.67em) 263 | #page_main 264 | max-width: 1200px; 265 | 266 | @media (min-width: 34em) 267 | .page 268 | width: calc(98% - 165px); 269 | float: right; 270 | margin-right: 0; 271 | if hexo-config('box_shadow') && hexo-config('box_shadow.enable') 272 | -webkit-box-shadow: 0 4px 8px 6px rgba(7,17,27,0.06); 273 | box-shadow: 0 4px 8px 6px rgba(7,17,27,0.06); 274 | .page-title 275 | padding 0 3.6rem 276 | article 277 | padding 0 3.6rem 3.6rem; 278 | 279 | 280 | // sidebar 281 | //------------------------------------------------ 282 | .side-card 283 | clear: both; 284 | margin-bottom: 1.6rem; 285 | -webkit-transform: translate3d(0, 0, 0); 286 | transform: translate3d(0, 0, 0); 287 | .card-wrap 288 | padding-left: 10px; 289 | img 290 | width: 100%; 291 | p, 292 | li 293 | font-size: 1.4rem; 294 | line-height: 1.5; 295 | 296 | .author-avatar 297 | display: table-cell; 298 | vertical-align: top; 299 | width: 40px; 300 | height: 40px; 301 | img 302 | width: 100%; 303 | max-width: 110px; 304 | border-radius: 50%; 305 | 306 | .author-discrip 307 | display: table-cell; 308 | vertical-align: top; 309 | padding-left: 15px; 310 | padding-right: 15px; 311 | line-height: 1; 312 | h3 313 | margin: 0px; 314 | font-size 1.8rem 315 | .author-bio 316 | font-size: 1.2rem; 317 | margin: .3rem 0; 318 | 319 | .author-links 320 | display: table-cell; 321 | position: relative; 322 | vertical-align: top; 323 | z-index: 10; 324 | cursor: pointer; 325 | li 326 | white-space: nowrap; 327 | margin-bottom: 0.5em; 328 | a 329 | margin-bottom: 5px; 330 | padding-right: 5px; 331 | padding-top: 2px; 332 | padding-bottom: 2px; 333 | color: inherit; 334 | font-size: 1.4rem; 335 | text-decoration: none; 336 | button 337 | margin-bottom: 0px; 338 | 339 | .btn 340 | display: inline-block; 341 | margin-bottom: 0.25em; 342 | font-size: 0.75em; 343 | font-weight: bold; 344 | text-align: center; 345 | background-color: rgb(122, 130, 136); 346 | cursor: pointer; 347 | color: rgb(255, 255, 255) !important; 348 | padding: 0.6em 1em; 349 | text-decoration: none; 350 | border-radius: 4px; 351 | border-width: 0px !important; 352 | border-style: initial !important; 353 | border-color: initial !important; 354 | border-image: initial !important; 355 | &:hover 356 | background-color: rgb(51, 51, 51); 357 | 358 | .m-social-links 359 | background-color: rgb(255, 255, 255); 360 | color: rgb(122, 130, 136) !important; 361 | border-width: 1px !important; 362 | border-style: solid !important; 363 | border-color: rgb(189, 193, 196) !important; 364 | border-image: initial !important; 365 | &:hover 366 | color: rgb(255, 255, 255) !important; 367 | 368 | .social-icons 369 | visibility hidden 370 | opacity 0 371 | position: absolute; 372 | right: 0; 373 | width: 115px; 374 | margin-top: 15px; 375 | padding-top: 8px; 376 | padding-left: 10px; 377 | list-style-type: none; 378 | border: 1px solid #f2f3f3; 379 | border-radius: 4px; 380 | background: #fff; 381 | z-index: -1; 382 | box-shadow: 0 0 10px rgba(0,0,0,0.25); 383 | cursor: default; 384 | transition: all ease-in-out 0.2s; 385 | &::before 386 | display: block; 387 | content: ""; 388 | position: absolute; 389 | top: -10px; 390 | left: calc(50% + 15px); 391 | width: 0px; 392 | z-index: 0; 393 | border-style: solid; 394 | border-width: 0px 10px 10px; 395 | border-color: rgb(255, 255, 255) transparent; 396 | transition: all 0.2s ease-in-out; 397 | a 398 | font-size 1.7rem 399 | li 400 | display: inline-block; 401 | .fa, 402 | .fas, 403 | .fab 404 | display: inline-block; 405 | font-size: inherit; 406 | text-rendering: auto; 407 | -webkit-font-smoothing: antialiased; 408 | -moz-osx-font-smoothing: grayscale; 409 | color: black; 410 | width: 1.28571em; 411 | text-align: center; 412 | -webkit-transition: all 0.2s ease-in-out; 413 | transition: all 0.2s ease-in-out; 414 | &:hover 415 | color: $theme-red; 416 | 417 | .is-open .social-icons 418 | visibility visible 419 | opacity 1 420 | 421 | .social-links 422 | display none 423 | list-style-type none 424 | cursor default 425 | -webkit-transition: all 0.2s ease-in-out; 426 | transition: all 0.2s ease-in-out; 427 | 428 | .e-social-link 429 | color black 430 | .fa, 431 | .fas, 432 | .fab 433 | padding-right 0.5rem 434 | &:hover span 435 | text-decoration underline 436 | 437 | .cv-links 438 | color: $theme-dark-blue !important 439 | display: inline-block; 440 | position: relative; 441 | font-size: 1.4rem; 442 | margin-left: 5.5rem; 443 | i 444 | text-decoration: underline; 445 | &::before 446 | margin-right: .5rem 447 | 448 | @media (min-width: 66.67em) 449 | .side-card 450 | padding-right: 0; 451 | 452 | @media (min-width: 34em) 453 | .side-card 454 | width: 165px; 455 | float: left; 456 | margin-right: 1.69492%; 457 | opacity: 0.75; 458 | -webkit-transition: opacity 0.2s ease-in-out; 459 | transition: opacity 0.2s ease-in-out; 460 | if hexo-config('box_shadow') && hexo-config('box_shadow.enable') 461 | -webkit-box-shadow: 0 4px 8px 6px rgba(7,17,27,0.06); 462 | box-shadow: 0 4px 8px 6px rgba(7,17,27,0.06); 463 | .card-wrap 464 | padding: 10px 10px 10px 17px; 465 | 466 | .sticky 467 | clear: both; 468 | position: -webkit-sticky; 469 | position: sticky; 470 | top: 2em; 471 | &>* 472 | display: block; 473 | 474 | .author-avatar 475 | display: block; 476 | width: auto; 477 | height: auto; 478 | text-align: center; 479 | img 480 | padding: 5px; 481 | border: 1px solid #f2f3f3; 482 | 483 | .author-discrip 484 | display: block; 485 | width: 100%; 486 | padding-left: 0; 487 | padding-right: 0; 488 | color: black; 489 | .author-bio 490 | font-size: 1.4rem 491 | margin-top: 8px; 492 | margin-bottom: 10px; 493 | 494 | .author-links 495 | display: block; 496 | 497 | .social-icons 498 | display: block; 499 | visibility visible 500 | opacity 1 501 | position: relative; 502 | width: auto; 503 | margin: 0; 504 | padding: 0; 505 | border: 0; 506 | background: transparent; 507 | box-shadow: none; 508 | &::before 509 | content none 510 | 511 | .m-social-links 512 | display none 513 | 514 | .social-links 515 | display block 516 | margin-top .8rem 517 | margin-bottom 1.6rem 518 | padding 0 519 | 520 | .cv-links 521 | margin: 0; 522 | 523 | // footer 524 | //------------------------------------------------ 525 | #page_footer 526 | clear: both; 527 | height: 100px 528 | width: 100%; 529 | float: left; 530 | margin-left: 0; 531 | margin-right: 0; 532 | //margin-top: -100px; 533 | color: #9ba1a6; 534 | -webkit-animation: intro 0.3s both; 535 | animation: intro 0.3s both; 536 | -webkit-animation-delay: 0.45s; 537 | animation-delay: 0.45s; 538 | background-color: #f2f3f3; 539 | border-top: 1px solid #bdc1c4; 540 | a 541 | color: #9ba1a6; 542 | -webkit-transition: all 0.2s ease-in-out; 543 | transition: all 0.2s ease-in-out; 544 | &:hover 545 | color: black; 546 | 547 | .footer_wrap 548 | max-width: 600px; 549 | margin-left: auto; 550 | margin-right: auto; 551 | clear: both; 552 | margin-top: 2em; 553 | padding-left: 2.5em; 554 | font-size: 1.28rem; 555 | 556 | @media (min-width: 66.67em) 557 | .footer_wrap 558 | max-width: 1200px; 559 | 560 | @media (min-width: 34em) 561 | .footer_wrap 562 | padding: 0 1em 2em; 563 | 564 | // mobile-nav 565 | //------------------------------------------------ 566 | .nav-wrap 567 | position fixed 568 | bottom 220px 569 | right 0 570 | max-width 50px 571 | visibility hidden 572 | opacity 0 573 | transition: all .3s; 574 | -webkit-transition: all .3s; 575 | -moz-transition: all .3s; 576 | &.is-visible 577 | visibility visible 578 | opacity 1 579 | pointer-events auto 580 | 581 | .nav 582 | height 30px 583 | width 30px 584 | 585 | .site-nav 586 | position: absolute; 587 | height: 30px; 588 | width: 30px; 589 | background-color: rgb(122, 130, 136); 590 | color: rgb(255, 255, 255); 591 | cursor: pointer; 592 | padding: 0px 0.3rem; 593 | border-width: 0px; 594 | border-style: initial; 595 | border-color: initial; 596 | border-image: initial; 597 | outline: none; 598 | 599 | .navicon 600 | position: relative; 601 | width: 18px; 602 | height: 3px; 603 | background: rgb(255, 255, 255); 604 | margin: auto; 605 | transition: all 0.3s ease 0s; 606 | &::before 607 | content: ""; 608 | position: absolute; 609 | top: -8px; 610 | left: 0px; 611 | width: 18px; 612 | height: 3px; 613 | background: rgb(255, 255, 255); 614 | transition: all 0.3s ease 0s; 615 | &::after 616 | content: ""; 617 | position: absolute; 618 | bottom: -8px; 619 | left: 0px; 620 | width: 18px; 621 | height: 3px; 622 | background: rgb(255, 255, 255); 623 | transition: all 0.3s ease 0s; 624 | 625 | .nav-open .navicon 626 | background: transparent; 627 | &::before 628 | transform-origin: 50% 50%; 629 | top: 0px; 630 | left: -3px; 631 | width: 25px; 632 | transform: rotate3d(0, 0, 1, 45deg); 633 | &::after 634 | transform-origin: 50% 50%; 635 | top: 0px; 636 | left: -3px; 637 | width: 25px; 638 | transform: rotate3d(0, 0, 1, -45deg); 639 | 640 | .nav_items 641 | visibility: hidden; 642 | opacity: 0; 643 | position: absolute; 644 | right: 45px; 645 | top: -20px; 646 | margin: 0; 647 | box-shadow: rgba(0, 0, 0, 0.25) 0px 0px 10px; 648 | padding: 5px; 649 | border-width: 1px; 650 | border-style: solid; 651 | border-color: rgb(242, 243, 243); 652 | border-image: initial; 653 | border-radius: 4px; 654 | background: rgb(255, 255, 255); 655 | list-style: none; 656 | transition: all ease-in-out 0.2s; 657 | li 658 | display: block; 659 | border-bottom: 1px solid rgb(242, 243, 243); 660 | a 661 | display: block; 662 | color: rgb(122, 130, 136); 663 | font-size: 1.6rem; 664 | margin: 0px; 665 | padding: 10px 20px; 666 | text-decoration: none; 667 | transition: all 0.2s ease-in-out 0s; 668 | &:hover 669 | color: rgb(92, 98, 102); 670 | background: rgb(222, 224, 225); 671 | &::before 672 | content: ""; 673 | position: absolute; 674 | top: 20px; 675 | right: -10px; 676 | width: 0px; 677 | display: block; 678 | z-index: 0; 679 | border-style: solid; 680 | border-width: 10px 0px 10px 10px; 681 | border-color: transparent transparent transparent white; 682 | &::after 683 | clear: both; 684 | content: ""; 685 | display: table; 686 | 687 | .nav-open .nav_items 688 | visibility visible 689 | opacity 1 690 | 691 | .cd-top 692 | display block 693 | width auto 694 | height auto 695 | i 696 | display: block; 697 | margin-top: 3px; 698 | width: 30px; 699 | height: 30px; 700 | background-color: #7a8288; 701 | color: #fff; 702 | text-align: center; 703 | text-decoration: none; 704 | font-size: 16px; 705 | line-height: 29px; 706 | cursor: pointer; 707 | 708 | 709 | // scrollbar 710 | //------------------------------------------------ 711 | ::-webkit-scrollbar 712 | width: 12px; 713 | height: 8px; 714 | background-color: white; 715 | 716 | ::-webkit-scrollbar-track 717 | //border-radius: 10px; 718 | background-color: white; 719 | 720 | ::-webkit-scrollbar-thumb 721 | //border-radius: 10px; 722 | background-color: rgba(122, 130, 136, 0.4); 723 | -------------------------------------------------------------------------------- /themes/Academia/source/css/user.styl: -------------------------------------------------------------------------------- 1 | //customize your own CSS for page display -------------------------------------------------------------------------------- /themes/Academia/source/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hangvane/academia-hexo-netlify-cms-vercel/ba85629d4292d3df792a5860c9c52a5e83595e6d/themes/Academia/source/img/favicon.png -------------------------------------------------------------------------------- /themes/Academia/source/img/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hangvane/academia-hexo-netlify-cms-vercel/ba85629d4292d3df792a5860c9c52a5e83595e6d/themes/Academia/source/img/profile.png -------------------------------------------------------------------------------- /themes/Academia/source/js/main.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | // menu 3 | $(".menus_icon").click(function () { 4 | if ($(".header_wrap").hasClass("menus-open")) { 5 | $(".header_wrap").removeClass("menus-open").addClass("menus-close") 6 | } else { 7 | $(".header_wrap").removeClass("menus-close").addClass("menus-open") 8 | } 9 | }) 10 | 11 | $(".m-social-links").click(function () { 12 | if ($(".author-links").hasClass("is-open")) { 13 | $(".author-links").removeClass("is-open").addClass("is-close") 14 | } else { 15 | $(".author-links").removeClass("is-close").addClass("is-open") 16 | } 17 | }) 18 | 19 | $(".site-nav").click(function () { 20 | if ($(".nav").hasClass("nav-open")) { 21 | $(".nav").removeClass("nav-open").addClass("nav-close") 22 | } else { 23 | $(".nav").removeClass("nav-close").addClass("nav-open") 24 | } 25 | }) 26 | 27 | $(document).click(function(e){ 28 | var target = $(e.target); 29 | if(target.closest(".nav").length != 0) return; 30 | $(".nav").removeClass("nav-open").addClass("nav-close") 31 | if(target.closest(".author-links").length != 0) return; 32 | $(".author-links").removeClass("is-open").addClass("is-close") 33 | if((target.closest(".menus_icon").length != 0) || (target.closest(".menus_items").length != 0)) return; 34 | $(".header_wrap").removeClass("menus-open").addClass("menus-close") 35 | }) 36 | 37 | // 显示 cdtop 38 | $(document).ready(function ($) { 39 | var offset = 100, 40 | scroll_top_duration = 700, 41 | $back_to_top = $('.nav-wrap'); 42 | 43 | $(window).scroll(function () { 44 | ($(this).scrollTop() > offset) ? $back_to_top.addClass('is-visible') : $back_to_top.removeClass('is-visible'); 45 | }); 46 | 47 | $(".cd-top").on('click', function (event) { 48 | event.preventDefault(); 49 | $('body,html').animate({ 50 | scrollTop: 0, 51 | }, scroll_top_duration); 52 | }); 53 | }); 54 | 55 | // pjax 56 | $(document).pjax('a[target!=_blank]','.page', { 57 | fragment: '.page', 58 | timeout: 5000 59 | }); 60 | $(document).on({ 61 | 'pjax:click': function() { 62 | $('body,html').animate({ 63 | scrollTop: 0, 64 | }, 700); 65 | }, 66 | 'pjax:end': function() { 67 | if ($(".header_wrap").hasClass("menus-open")) { 68 | $(".header_wrap").removeClass("menus-open").addClass("menus-close") 69 | } 70 | if ($(".author-links").hasClass("is-open")) { 71 | $(".author-links").removeClass("is-open").addClass("is-close") 72 | } 73 | if ($(".nav").hasClass("nav-open")) { 74 | $(".nav").removeClass("nav-open").addClass("nav-close") 75 | } 76 | } 77 | }); 78 | 79 | // smooth scroll 80 | $(function () { 81 | $('a[href*=\\#]:not([href=\\#])').click(function () { 82 | if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) { 83 | var target = $(this.hash); 84 | target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); 85 | if (target.length) { 86 | $('html,body').animate({ 87 | scrollTop: target.offset().top 88 | }, 700); 89 | return false; 90 | } 91 | } 92 | }); 93 | }); 94 | 95 | }) 96 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [ 3 | { "source": "/auth", "destination": "/api/auth.ts" }, 4 | { "source": "/callback", "destination": "/api/callback.ts" } 5 | ] 6 | } 7 | --------------------------------------------------------------------------------