mirror of
https://github.com/next-theme/hexo-theme-next.git
synced 2026-11-13 04:39:31 +00:00
Compare commits
No commits in common. "master" and "v8.29.1" have entirely different histories.
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://hexo.io)
|
[](https://hexo.io)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
||||||
@ -36,9 +36,7 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Requires Hexo 8.0.0 or later and Node.js `^22.13.0 || >=24.0.0`.
|
If you're using Hexo 5.0 or later, the simplest way to install is through npm:
|
||||||
|
|
||||||
The simplest way to install is through npm:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd hexo-site
|
cd hexo-site
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://hexo.io)
|
[](https://hexo.io)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
||||||
@ -36,9 +36,7 @@
|
|||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
|
||||||
Требуются Hexo 8.0.0 или новее и Node.js `^22.13.0 || >=24.0.0`.
|
If you're using Hexo 5.0 or later, the simplest way to install is through npm:
|
||||||
|
|
||||||
Самый простой способ установки — через npm:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd hexo-site
|
cd hexo-site
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://www.npmjs.com/package/hexo-theme-next)
|
[](https://www.npmjs.com/package/hexo-theme-next)
|
||||||
[](https://hexo.io)
|
[](https://hexo.io)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
[](https://github.com/next-theme/hexo-theme-next/blob/master/LICENSE.md)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ALinter)
|
||||||
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
[](https://github.com/next-theme/hexo-theme-next/actions?query=workflow%3ATester)
|
||||||
@ -36,9 +36,7 @@
|
|||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
需要 Hexo 8.0.0 或更新版本,以及 Node.js `^22.13.0 || >=24.0.0`。
|
如果你在使用 Hexo 5.0 或更新版本,最简单的安装方式是通过 npm:
|
||||||
|
|
||||||
最简单的安装方式是通过 npm:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd hexo-site
|
cd hexo-site
|
||||||
|
|||||||
@ -34,9 +34,6 @@
|
|||||||
"url": "https://github.com/next-theme/hexo-theme-next/issues"
|
"url": "https://github.com/next-theme/hexo-theme-next/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://theme-next.js.org",
|
"homepage": "https://theme-next.js.org",
|
||||||
"engines": {
|
|
||||||
"node": "^22.13.0 || >=24.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next-theme/eslint-config": "0.0.5",
|
"@next-theme/eslint-config": "0.0.5",
|
||||||
"c8": "12.0.0",
|
"c8": "12.0.0",
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { parse } = require('url');
|
||||||
const { unescapeHTML } = require('hexo-util');
|
const { unescapeHTML } = require('hexo-util');
|
||||||
|
|
||||||
hexo.extend.filter.register('after_post_render', data => {
|
hexo.extend.filter.register('after_post_render', data => {
|
||||||
@ -12,7 +13,7 @@ hexo.extend.filter.register('after_post_render', data => {
|
|||||||
data.content = data.content.replace(/(<img[^>]*)\ssrc=/ig, '$1 data-src=');
|
data.content = data.content.replace(/(<img[^>]*)\ssrc=/ig, '$1 data-src=');
|
||||||
}
|
}
|
||||||
if (theme.exturl) {
|
if (theme.exturl) {
|
||||||
const siteHost = URL.parse(config.url)?.hostname || config.url;
|
const siteHost = parse(config.url).hostname || config.url;
|
||||||
// External URL icon
|
// External URL icon
|
||||||
const exturlIcon = theme.exturl_icon ? '<i class="fa fa-external-link-alt"></i>' : '';
|
const exturlIcon = theme.exturl_icon ? '<i class="fa fa-external-link-alt"></i>' : '';
|
||||||
data.content = data.content.replace(/<a[^>]*\shref="([^"]+)"[^>]*>([^<]+)<\/a>/ig, (match, href, html) => {
|
data.content = data.content.replace(/<a[^>]*\shref="([^"]+)"[^>]*>([^<]+)<\/a>/ig, (match, href, html) => {
|
||||||
@ -20,8 +21,8 @@ hexo.extend.filter.register('after_post_render', data => {
|
|||||||
if (!href) return match;
|
if (!href) return match;
|
||||||
|
|
||||||
// Exit if the url has same host with `config.url`, which means it's an internal link.
|
// Exit if the url has same host with `config.url`, which means it's an internal link.
|
||||||
const link = URL.parse(href);
|
const link = parse(href);
|
||||||
if (!link?.protocol || link.hostname === siteHost) return match;
|
if (!link.protocol || link.hostname === siteHost) return match;
|
||||||
|
|
||||||
// Return encrypted URL with title.
|
// Return encrypted URL with title.
|
||||||
const title = match.match(/title="([^"]+)"/);
|
const title = match.match(/title="([^"]+)"/);
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
const { parse } = require('url');
|
||||||
const nextFont = require('./font');
|
const nextFont = require('./font');
|
||||||
const nextUrl = require('./next-url');
|
const nextUrl = require('./next-url');
|
||||||
const { getVendors } = require('../events/lib/utils');
|
const { getVendors } = require('../events/lib/utils');
|
||||||
@ -57,22 +58,16 @@ hexo.extend.helper.register('next_data', function(name, ...data) {
|
|||||||
}</script>`;
|
}</script>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scheme and hostname of an absolute URL, or '' for a relative one.
|
|
||||||
function urlOrigin(url) {
|
|
||||||
const data = url && URL.parse(url);
|
|
||||||
return data?.hostname ? data.protocol + '//' + data.hostname : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
hexo.extend.helper.register('next_pre', function() {
|
hexo.extend.helper.register('next_pre', function() {
|
||||||
if (!this.theme.preconnect) return '';
|
if (!this.theme.preconnect) return '';
|
||||||
const { enable, host } = this.theme.font;
|
const { enable, host } = this.theme.font;
|
||||||
const { internal, plugins, custom_cdn_url } = this.theme.vendors;
|
const { internal, plugins, custom_cdn_url } = this.theme.vendors;
|
||||||
const links = {
|
const links = {
|
||||||
local : urlOrigin(this.theme.js),
|
local : this.theme.js && parse(this.theme.js).hostname ? parse(this.theme.js).protocol + '//' + parse(this.theme.js).hostname : '',
|
||||||
jsdelivr: 'https://cdn.jsdelivr.net',
|
jsdelivr: 'https://cdn.jsdelivr.net',
|
||||||
unpkg : 'https://unpkg.com',
|
unpkg : 'https://unpkg.com',
|
||||||
cdnjs : 'https://cdnjs.cloudflare.com',
|
cdnjs : 'https://cdnjs.cloudflare.com',
|
||||||
custom : urlOrigin(custom_cdn_url)
|
custom : custom_cdn_url && parse(custom_cdn_url).hostname ? parse(custom_cdn_url).protocol + '//' + parse(custom_cdn_url).hostname : ''
|
||||||
};
|
};
|
||||||
const h = enable ? host || 'https://fonts.googleapis.com' : '';
|
const h = enable ? host || 'https://fonts.googleapis.com' : '';
|
||||||
const i = links[internal];
|
const i = links[internal];
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { htmlTag } = require('hexo-util');
|
const { htmlTag } = require('hexo-util');
|
||||||
|
const { parse } = require('url');
|
||||||
|
|
||||||
module.exports = function(path, text, options = {}, decode = false) {
|
module.exports = function(path, text, options = {}, decode = false) {
|
||||||
const { config, theme } = this;
|
const { config, theme } = this;
|
||||||
const data = URL.parse(path);
|
const data = parse(path);
|
||||||
const siteHost = URL.parse(config.url)?.hostname || config.url;
|
const siteHost = parse(config.url).hostname || config.url;
|
||||||
|
|
||||||
let exturl = '';
|
let exturl = '';
|
||||||
let tag = 'a';
|
let tag = 'a';
|
||||||
let attrs = { href: this.url_for(path) };
|
let attrs = { href: this.url_for(path) };
|
||||||
|
|
||||||
// If `exturl` enabled, set spanned links only on external links.
|
// If `exturl` enabled, set spanned links only on external links.
|
||||||
if (theme.exturl && data?.protocol && data.hostname !== siteHost) {
|
if (theme.exturl && data.protocol && data.hostname !== siteHost) {
|
||||||
tag = 'span';
|
tag = 'span';
|
||||||
exturl = 'exturl';
|
exturl = 'exturl';
|
||||||
const encoded = Buffer.from(path).toString('base64');
|
const encoded = Buffer.from(path).toString('base64');
|
||||||
@ -36,7 +37,7 @@ module.exports = function(path, text, options = {}, decode = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If it's external link, rewrite attributes.
|
// If it's external link, rewrite attributes.
|
||||||
if (data?.protocol && data.hostname !== siteHost) {
|
if (data.protocol && data.hostname !== siteHost) {
|
||||||
attrs.external = null;
|
attrs.external = null;
|
||||||
|
|
||||||
if (!theme.exturl) {
|
if (!theme.exturl) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
.site-nav-toggle, .site-nav-search {
|
.site-nav-toggle, .site-nav-search {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
display: none;
|
display: none;
|
||||||
padding: 0 15px;
|
padding: 0 10px;
|
||||||
|
|
||||||
.fa {
|
.fa {
|
||||||
transition: transform .5s;
|
transition: transform .5s;
|
||||||
|
|||||||
@ -70,34 +70,4 @@ describe('engine', () => {
|
|||||||
it('does not apply script loading options to stylesheets', () => {
|
it('does not apply script loading options to stylesheets', () => {
|
||||||
nextVendors('stylesheet', { async: true }).should.eql('<link rel="stylesheet" href="https://cdn.example.com/library.css">');
|
nextVendors('stylesheet', { async: true }).should.eql('<link rel="stylesheet" href="https://cdn.example.com/library.css">');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('next_pre', () => {
|
|
||||||
const nextPre = (theme = {}) => helpers.next_pre.call({
|
|
||||||
theme: {
|
|
||||||
preconnect: true,
|
|
||||||
js : 'js',
|
|
||||||
font : { enable: false },
|
|
||||||
vendors : { internal: 'local', plugins: 'local', custom_cdn_url: '' },
|
|
||||||
...theme
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips a relative local script path', () => {
|
|
||||||
nextPre().should.eql('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the scheme and hostname of an absolute local script URL', () => {
|
|
||||||
nextPre({ js: 'https://static.example.com/next/js' }).should.eql('<link rel="preconnect" href="https://static.example.com" crossorigin>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('drops the port and path of a custom CDN URL', () => {
|
|
||||||
nextPre({
|
|
||||||
vendors: { internal: 'custom', plugins: 'custom', custom_cdn_url: 'https://Cdn.Example.com:8443/npm/${npm_name}@${version}/${minified}' }
|
|
||||||
}).should.eql('<link rel="preconnect" href="https://cdn.example.com" crossorigin>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips a protocol-relative custom CDN URL', () => {
|
|
||||||
nextPre({ vendors: { internal: 'custom', plugins: 'custom', custom_cdn_url: '//cdn.example.com' } }).should.eql('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -46,15 +46,4 @@ describe('next-url', () => {
|
|||||||
const encoded = btoa('https://theme-next.js.org');
|
const encoded = btoa('https://theme-next.js.org');
|
||||||
nextUrl('https://theme-next.js.org', 'Text', { class: 'theme-link' }).should.eql(`<span class="exturl theme-link" data-url="${encoded}">Text</span>`);
|
nextUrl('https://theme-next.js.org', 'Text', { class: 'theme-link' }).should.eql(`<span class="exturl theme-link" data-url="${encoded}">Text</span>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('relative and anchor links stay links with exturl enabled', () => {
|
|
||||||
hexo.theme.exturl = true;
|
|
||||||
nextUrl('/child/', 'Text').should.eql('<a href="/child/">Text</a>');
|
|
||||||
nextUrl('#comments', 'Text').should.eql('<a href="#comments">Text</a>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('an absolute link to the site itself is internal', () => {
|
|
||||||
hexo.theme.exturl = false;
|
|
||||||
nextUrl('https://EXAMPLE.com/about/', 'Text').should.eql('<a href="https://example.com/about/">Text</a>');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user