├── source
├── img
│ ├── top.png
│ ├── top.avif
│ ├── top.webp
│ ├── favicon.png
│ └── Transparent_Akkarin.png
├── fonts
│ └── roboto
│ │ ├── Roboto-Black.woff
│ │ ├── Roboto-Black.woff2
│ │ ├── Roboto-Bold.woff
│ │ ├── Roboto-Bold.woff2
│ │ ├── Roboto-Light.woff
│ │ ├── Roboto-Light.woff2
│ │ ├── Roboto-Medium.woff
│ │ ├── Roboto-Thin.woff
│ │ ├── Roboto-Thin.woff2
│ │ ├── Roboto-Medium.woff2
│ │ ├── Roboto-Regular.woff
│ │ ├── Roboto-Regular.woff2
│ │ ├── Roboto-BlackItalic.woff
│ │ ├── Roboto-BoldItalic.woff
│ │ ├── Roboto-BoldItalic.woff2
│ │ ├── Roboto-LightItalic.woff
│ │ ├── Roboto-ThinItalic.woff
│ │ ├── Roboto-ThinItalic.woff2
│ │ ├── Roboto-BlackItalic.woff2
│ │ ├── Roboto-LightItalic.woff2
│ │ ├── Roboto-MediumItalic.woff
│ │ ├── Roboto-MediumItalic.woff2
│ │ ├── Roboto-RegularItalic.woff
│ │ ├── Roboto-RegularItalic.woff2
│ │ └── LICENSE.txt
├── icons
│ └── material-icons
│ │ ├── MaterialIcons-Regular.woff
│ │ ├── MaterialIcons-Regular.woff2
│ │ ├── LICENSE.txt
│ │ └── MaterialIcons-Regular.ijmap
├── js
│ ├── bsz.min.js
│ ├── bsz.js
│ ├── medium-zoom.min.js
│ └── script.js
├── css
│ ├── prism-line-numbers.min.css
│ ├── prism-vsc-dark-plus.min.css
│ ├── style.css
│ └── APlayer.min.css
└── upgrade-browser.html
├── scripts
├── remove-index.js
├── is-css-color.js
├── async-css.js
├── marked-extend.js
├── mathjax-render.js
├── aplayer.js
├── minify.js
└── img-blur.js
├── layout
├── tag.ejs
├── category.ejs
├── index.ejs
├── partials
│ ├── import-js.ejs
│ ├── home-banner.ejs
│ ├── top.ejs
│ ├── footer.ejs
│ ├── paginator.ejs
│ ├── import-css.ejs
│ ├── post-entry.ejs
│ ├── comment-area.ejs
│ ├── structured-data.ejs
│ └── navigation-drawer.ejs
├── archive.ejs
├── links.ejs
├── post.ejs
└── layout.ejs
├── package.json
├── .gitignore
├── _config.yml
└── README.md
/source/img/top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/img/top.png
--------------------------------------------------------------------------------
/source/img/top.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/img/top.avif
--------------------------------------------------------------------------------
/source/img/top.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/img/top.webp
--------------------------------------------------------------------------------
/source/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/img/favicon.png
--------------------------------------------------------------------------------
/source/img/Transparent_Akkarin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/img/Transparent_Akkarin.png
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Black.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Black.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Bold.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Bold.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Light.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Light.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Medium.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Thin.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Thin.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Medium.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Regular.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-BlackItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-BlackItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-BoldItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-BoldItalic.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-LightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-LightItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-ThinItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-ThinItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-ThinItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-ThinItalic.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-BlackItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-BlackItalic.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-LightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-LightItalic.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-MediumItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-MediumItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-MediumItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-MediumItalic.woff2
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-RegularItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-RegularItalic.woff
--------------------------------------------------------------------------------
/source/fonts/roboto/Roboto-RegularItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/fonts/roboto/Roboto-RegularItalic.woff2
--------------------------------------------------------------------------------
/scripts/remove-index.js:
--------------------------------------------------------------------------------
1 | hexo.extend.helper.register(
2 | 'removeIndex',
3 | str => str.endsWith('/index.html') ? str.replace(/\/index\.html$/, '/') : str,
4 | );
--------------------------------------------------------------------------------
/source/icons/material-icons/MaterialIcons-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/icons/material-icons/MaterialIcons-Regular.woff
--------------------------------------------------------------------------------
/source/icons/material-icons/MaterialIcons-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransparentLC/hexo-theme-akarin/HEAD/source/icons/material-icons/MaterialIcons-Regular.woff2
--------------------------------------------------------------------------------
/layout/tag.ejs:
--------------------------------------------------------------------------------
1 | <% page.posts.each(post => { %>
2 | <%- partial('partials/post-entry', { post }) %>
3 | <% }); %>
4 |
5 |
6 | <%- partial('partials/paginator') %>
--------------------------------------------------------------------------------
/layout/category.ejs:
--------------------------------------------------------------------------------
1 | <% page.posts.each(post => { %>
2 | <%- partial('partials/post-entry', { post }) %>
3 | <% }); %>
4 |
5 |
6 | <%- partial('partials/paginator') %>
--------------------------------------------------------------------------------
/layout/index.ejs:
--------------------------------------------------------------------------------
1 | <% if (page.posts.length > 0) { %>
2 | <% page.posts.sort('date', -1).limit(10).each(post => { %>
3 | <%- partial('partials/post-entry', { post }) %>
4 | <% }); %>
5 | <% } %>
6 |
7 |
8 | <%- partial('partials/paginator') %>
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "engine": {
3 | "node": ">=18.0.0"
4 | },
5 | "dependencies": {
6 | "@swc/core": "^1.11.16",
7 | "html-minifier-terser": "^7.2.0",
8 | "lightningcss": "^1.29.3",
9 | "mathjax": "^3.2.2",
10 | "sharp": "^0.34.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/source/js/bsz.min.js:
--------------------------------------------------------------------------------
1 | (e=>{let n=n=>e.getElementById(n)||{style:{}},t=["site_pv","site_uv","page_pv"];_=e=>{delete _,t.forEach(t=>n("busuanzi_value_"+t).innerText=e[t])};let i=(i,o)=>{t.forEach(e=>n("busuanzi_container_"+e).style.display=o?"inline":"none"),e.body.removeChild(i)},o=e.createElement("script");o.onload=()=>i(o,!0),o.onerror=()=>i(o,!1),o.src="https://busuanzi.ibruce.info/busuanzi?jsonpCallback=_",e.body.appendChild(o)})(document)
--------------------------------------------------------------------------------
/scripts/is-css-color.js:
--------------------------------------------------------------------------------
1 | // How to identify a given string is hex color format
2 | // https://stackoverflow.com/questions/1636350/how-to-identify-a-given-string-is-hex-color-format#answer-13624916
3 | hexo.extend.helper.register(
4 | 'isCssColor',
5 | str => str.match(
6 | /^(#[a-f0-9]{6}|#[a-f0-9]{3}|rgb *\( *[0-9]{1,3}%? *, *[0-9]{1,3}%? *, *[0-9]{1,3}%? *\)|rgba *\( *[0-9]{1,3}%? *, *[0-9]{1,3}%? *, *[0-9]{1,3}%? *, *[0-9]{1,3}%? *\))$/i
7 | )
8 | );
--------------------------------------------------------------------------------
/scripts/async-css.js:
--------------------------------------------------------------------------------
1 | hexo.extend.helper.register(
2 | 'async_css',
3 | function (args) {
4 | return ((typeof args === 'string' || args instanceof String) ? [args] : args)
5 | .map(e => (typeof e === 'string' || e instanceof String) ? ({ href: e }) : e)
6 | .map(e => e.sync ? this.css(e) : ``)
7 | .join('');
8 | },
9 | );
--------------------------------------------------------------------------------
/layout/partials/import-js.ejs:
--------------------------------------------------------------------------------
1 | <% if (theme.scripts) { %>
2 | <%- js(theme.scripts) %>
3 | <% } %>
4 |
5 | <% if (theme.aplayer.script) { %>
6 |
7 | <% } %>
8 |
9 | <% if (theme.stats.busuanzi.enable) { %>
10 | <%-
11 | js({
12 | src: theme.stats.busuanzi.script || 'https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js',
13 | async: true,
14 | })
15 | %>
16 | <% } %>
--------------------------------------------------------------------------------
/source/css/prism-line-numbers.min.css:
--------------------------------------------------------------------------------
1 | pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
--------------------------------------------------------------------------------
/layout/partials/home-banner.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%- config.title %>
5 |
6 |
7 |
8 | <%- Array.isArray(theme.uiux.slogan) ? theme.uiux.slogan.join('
') : theme.uiux.slogan %>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/layout/partials/top.ejs:
--------------------------------------------------------------------------------
1 | <% if (theme.uiux.top.enable) { %>
2 | <% if (theme.uiux.top.style === 'akarin') { %>
3 |
4 |
5 |
6 |
7 |
8 | <% } else if (theme.uiux.top.style === 'fab') { %>
9 |
14 | <% } %>
15 | <% } %>
16 |
--------------------------------------------------------------------------------
/source/upgrade-browser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 是时候升级你的浏览器了
8 |
9 |
10 | 是时候升级你的浏览器了
11 | 本站使用了最新的 Web 技术,使用陈旧的 Internet Explorer 浏览器将无法访问本站。
12 | Microsoft 已从 2022 年 6 月 15 日起终止了对 Internet Explorer 11 的支持。
13 | 本站推荐你使用 Firefox 或 Microsoft Edge,享受快速、安全和现代的上网体验。
14 |
15 |
--------------------------------------------------------------------------------
/layout/partials/footer.ejs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/marked-extend.js:
--------------------------------------------------------------------------------
1 | hexo.extend.filter.register('marked:renderer', renderer => {
2 | renderer.image = (href, title, text) => `
3 |
9 |
17 |
18 | `;
19 | renderer.table = (header, body) => `
20 |
21 |
22 | ${header}
23 | ${body}
24 |
25 |
26 | `;
27 | });
--------------------------------------------------------------------------------
/source/js/bsz.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 这是使用ES6重写的不蒜子的原版JS的简化版,minify以后的文件大小只有424 Bytes,是原版的1884 Bytes的22.5%。
3 | * 原版:https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js
4 | * 简化版和原版一样,实现了以下功能:
5 | * 1. 在busuanzi_value_***中写入计数
6 | * 2. 获取计数成功/失败后,将busuanzi_container_***的display设为inline/none
7 | * 3. 执行后,自动清理为了使用JSONP而在window上添加的函数和插入的
26 |
29 | `;
30 | };
31 |
32 | hexo.extend.tag.register(
33 | 'aplayerlite',
34 | /**
35 | * @param {String[]} args
36 | * @returns {String}
37 | */
38 | args => {
39 | const [title, author, url, cover, lrc] = args;
40 | const aplayerConfig = {
41 | audio: {
42 | title,
43 | author,
44 | url,
45 | cover,
46 | },
47 | };
48 | if (lrc) {
49 | aplayerConfig.lrcType = 3;
50 | aplayerConfig.audio.lrc = lrc;
51 | }
52 | return createAPlayerHTML(aplayerConfig);
53 | },
54 | );
55 |
56 | hexo.extend.tag.register(
57 | 'aplayerlitelrc',
58 | /**
59 | * @param {String[]} args
60 | * @param {String} content
61 | * @returns {String}
62 | */
63 | (args, content) => {
64 | const [title, author, url, cover] = args;
65 | const aplayerConfig = {
66 | lrcType: 1,
67 | audio: {
68 | title,
69 | author,
70 | url,
71 | cover,
72 | lrc: content,
73 | },
74 | };
75 | return createAPlayerHTML(aplayerConfig);
76 | },
77 | {
78 | ends: true,
79 | },
80 | );
81 |
82 | hexo.extend.filter.register('after_render:html', (str, data) => {
83 | if (str.includes('
11 |
12 | <% } %>
13 |
14 | <% if (theme.comment.artalk.enable) { %>
15 |
16 |
63 | <% } %>
--------------------------------------------------------------------------------
/layout/partials/structured-data.ejs:
--------------------------------------------------------------------------------
1 | <% if((page.current === 1) && is_home()) { %>
2 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | <% } %>
31 |
32 | <% if (is_post()) { %>
33 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | <% if ((theme.head.keywords ? [theme.head.keywords] : []).concat(page.tags ? page.tags.data.map(e => e.name) : []).length) { %>
73 | <% (theme.head.keywords ? [theme.head.keywords] : []).concat(page.tags ? page.tags.data.map(e => e.name) : []).forEach(e => { %>
74 |
75 | <% }) %>
76 | <% } %>
77 | <% } %>
--------------------------------------------------------------------------------
/scripts/minify.js:
--------------------------------------------------------------------------------
1 | const htmlMinifier = require('html-minifier-terser');
2 | const lightningcss = require('lightningcss');
3 | const swc = require('@swc/core');
4 |
5 | const encoder = new TextEncoder;
6 | const decoder = new TextDecoder;
7 |
8 | hexo.extend.filter.register('after_render:html', async (str, data) => {
9 | if (!hexo.theme.config.minify_html.enable) return str;
10 | const minified = await htmlMinifier.minify(str, {
11 | collapseWhitespace: true,
12 | collapseBooleanAttributes: true,
13 | decodeEntities: true,
14 | removeComments: true,
15 | removeRedundantAttributes: true,
16 | removeScriptTypeAttributes: true,
17 | removeStyleLinkTypeAttributes: true,
18 | removeEmptyAttributes: true,
19 | useShortDoctype: true,
20 | sortAttributes: true,
21 | sortClassName: true,
22 | processConditionalComments: true,
23 | processScripts: [
24 | 'application/ld+json',
25 | ],
26 | /**
27 | * @param {String} text
28 | * @param {'inline' | 'media' | undefined} type
29 | * @returns {String}
30 | */
31 | minifyCSS: (text, type) => {
32 | // function wrapCSS(text, type)
33 | // https://github.com/terser/html-minifier-terser/blob/c4a7ae0bd08b1a438d9ca12a229b4cbe93fc016a/src/htmlminifier.js#L355
34 | switch (type) {
35 | case 'inline':
36 | text = `*{${text}}`;
37 | break;
38 | case 'media':
39 | text = `@media ${text}{a{top:0}}`;
40 | break;
41 | }
42 | const minified = decoder.decode(lightningcss.transform({ code: encoder.encode(text), minify: true }).code);
43 | // function unwrapCSS(text, type)
44 | // https://github.com/terser/html-minifier-terser/blob/c4a7ae0bd08b1a438d9ca12a229b4cbe93fc016a/src/htmlminifier.js#L366
45 | /** @type {RegExpMatchArray | null} */
46 | let m;
47 | switch (type) {
48 | case 'inline':
49 | m = minified.match(/^\*\{([\s\S]*)\}$/);
50 | return m ? m[1] : minified;
51 | case 'media':
52 | m = minified.match(/^@media ([\s\S]*?)\s*{[\s\S]*}$/);
53 | return m ? m[1] : minified;
54 | default:
55 | return minified;
56 | }
57 | },
58 | /**
59 | * @param {String} text
60 | * @param {Boolean} inline
61 | * @returns {String}
62 | */
63 | minifyJS: async (text, inline) => await swc.minify(text, {
64 | compress: {
65 | // https://github.com/swc-project/swc/blob/main/crates/swc_ecma_minifier/src/option/terser.rs
66 | // impl From for EsVersion
67 | ecma: 2022,
68 | arguments: true,
69 | unsafe_arrows: true,
70 | unsafe_math: true,
71 | unsafe_methods: true,
72 | unsafe_proto: true,
73 | unsafe_regexp: true,
74 | unsafe_symbols: true,
75 | unsafe_undefined: true,
76 | },
77 | mangle: true,
78 | format: {
79 | comments: false,
80 | },
81 | sourceMap: false,
82 | }).then(r => r.code),
83 | ...hexo.theme.config.minify_html,
84 | });
85 | hexo.log.debug(`Minified: \x1b[35m${data.path}\x1b[39m (\x1b[36m${str.length}\x1b[39m -> \x1b[36m${minified.length}\x1b[39m bytes, \x1b[36m${Math.round(minified.length / str.length * 1e4) / 1e2}%\x1b[39m)`);
86 | return minified;
87 | });
--------------------------------------------------------------------------------
/layout/post.ejs:
--------------------------------------------------------------------------------
1 |
2 |
5 | style="background-color:<%= page.thumbnail_color %>"
6 | <% } %>
7 | <% if (page.thumbnail) { %>
8 | data-src="<%= page.thumbnail %>"
9 | <% } %>
10 | <% if (page.thumbnail_webp) { %>
11 | data-src-webp="<%= page.thumbnail_webp %>"
12 | <% } %>
13 | <% if (page.thumbnail_avif) { %>
14 | data-src-avif="<%= page.thumbnail_avif %>"
15 | <% } %>
16 | <% if (page.thumbnail_jxl) { %>
17 | data-src-jxl="<%= page.thumbnail_jxl %>"
18 | <% } %>
19 | >
20 | <% if (page.thumbnail_color && !isCssColor(page.thumbnail_color)) { %>
21 |
25 | <% } %>
26 |
27 |
28 |
29 |
30 | <%= page.title || '[Untitled]' %>
31 |
32 | <% if (page.categories && page.categories.data.length > 0) { %>
33 |
34 | <% page.categories.data.forEach((category, i) => { %>
35 |
<%= category.name %>
39 | <% if (i + 1 < page.categories.data.length) { %>><% } %>
40 | <% }); %>
41 |
42 | <% } %>
43 |
44 |
45 |
46 |
64 |
65 | <%- page.content %>
66 |
67 | <% const license = page.hide_license ? '' : (page.license || theme.posts.license); %>
68 | <% if (license) { %>
69 |
70 | <%- license %>
71 |
72 | 本文作者:<%= page.author || config.author %>
73 |
74 | 本文链接:<%= removeIndex(page.permalink) %>
75 |
76 | <% } %>
77 |
78 | <% if (Object.keys(theme.comment).some(k => theme.comment[k].enable)) { %>
79 | <% if (page.comments) { %>
80 | <%- partial('partials/comment-area') %>
81 | <% } else { %>
82 |
评论已被作者关闭
83 | <% } %>
84 | <% } %>
85 |
86 |
87 |
88 | <% if (!is_page()) { %>
89 | <%- partial('partials/paginator') %>
90 | <% } %>
--------------------------------------------------------------------------------
/layout/layout.ejs:
--------------------------------------------------------------------------------
1 | <%
2 | let pageTitle = page.title || config.subtitle || '';
3 | if (is_tag()) {
4 | pageTitle = `标签:${page.tag}`;
5 | } else if (is_category()) {
6 | pageTitle = `分类:${page.category}`;
7 | } else if (is_archive()) {
8 | pageTitle = '归档';
9 | if (is_month()) {
10 | pageTitle += `:${page.year}-${page.month.toString().padStart(2, 0)}`;
11 | } else if (is_year()) {
12 | pageTitle += `:${page.year}`;
13 | }
14 | }
15 | pageTitle += (pageTitle ? ' | ' : '') + config.title;
16 |
17 | let description = config.description || '';
18 | if (is_post()) {
19 | description = strip_html(page.excerpt) || truncate(strip_html(page.content), { length: theme.posts.default_excerpt });
20 | }
21 |
22 | let keywords = (page.tags || []).map(e => e.name);
23 | if (theme.head.keywords) keywords.unshift(theme.head.keywords);
24 | keywords = keywords.join(',');
25 | %>
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | <% if (theme.head.site_verification.google) { %>
39 |
40 | <% } %>
41 | <% if (theme.head.site_verification.baidu) { %>
42 |
43 | <% } %>
44 |
45 |
46 |
47 |
48 | <% if (theme.rss) { %>
49 |
50 | <% } %>
51 |
52 | <% if (Array.isArray(theme.preconnect)) { %>
53 | <% theme.preconnect.forEach(domain => { %>
54 |
55 | <% }); %>
56 | <% } %>
57 | <% if (Array.isArray(theme.dns_prefetch)) { %>
58 | <% theme.dns_prefetch.forEach(domain => { %>
59 |
60 | <% }); %>
61 | <% } %>
62 | <% if (theme.uiux.sidebar_image_avif) { %>
63 |
64 | <% } else if (theme.uiux.sidebar_image_webp) { %>
65 |
66 | <% } else { %>
67 |
68 | <% } %>
69 | <% if (is_home() && page.current === 1) { %>
70 | <% if (theme.uiux.banner_image_avif) { %>
71 |
72 | <% } else if (theme.uiux.banner_image_webp) { %>
73 |
74 | <% } else { %>
75 |
76 | <% } %>
77 | <% } %>
78 |
79 |
80 | <%= pageTitle %>
81 |
82 | <% if (theme.head.structured_data) { %>
83 | <%- partial('partials/structured-data.ejs') %>
84 | <% } %>
85 |
86 |
87 |
88 |
89 | <%- partial('partials/import-css.ejs') %>
90 |
91 |
92 |
93 |
94 |
95 | <%- partial('partials/navigation-drawer') %>
96 |
97 |
98 | <%- partial('partials/top.ejs') %>
99 |
100 |
101 | <% if (is_home() && page.current === 1) { %>
102 | <%- partial('partials/home-banner.ejs') %>
103 | <% } else { %>
104 |
105 |
106 |
107 | <% } %>
108 |
109 |
110 |
111 | <%- body %>
112 |
113 |
114 |
115 | <%- partial('partials/footer.ejs') %>
116 |
117 |
118 | <%- partial('partials/import-js.ejs') %>
119 |
120 |
--------------------------------------------------------------------------------
/layout/partials/navigation-drawer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/scripts/img-blur.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const sharp = require('sharp');
4 |
5 | // Sharp v0.32.3 raises "heif: Invalid input" error while reading AVIF.
6 |
7 | /** @type {Record} */
8 | const thumbnailCache = {};
9 | const thumbnailCachePath = path.join(hexo.theme_dir, 'thumbnail-cache.json');
10 |
11 | hexo.log.debug(`Thumbnail cache path: \x1b[35m${thumbnailCachePath}\x1b[39m`);
12 |
13 | hexo.extend.filter.register('after_init', () => {
14 | if (!fs.existsSync(thumbnailCachePath)) return;
15 | Object.assign(thumbnailCache, JSON.parse(fs.readFileSync(thumbnailCachePath, { encoding: 'utf-8' })));
16 | });
17 |
18 | hexo.extend.filter.register('before_exit', () => {
19 | fs.writeFileSync(thumbnailCachePath, JSON.stringify(thumbnailCache));
20 | });
21 |
22 | /**
23 | * @param {String} source
24 | * @param {Number} size
25 | * @returns {Promise<{
26 | * thumbnailBase64: String,
27 | * width: Number,
28 | * height: Number,
29 | * }>}
30 | */
31 | const createThumbnail = async (source, size = 32) => {
32 | const cacheKey = `${source}:${size}`;
33 | if (cacheKey in thumbnailCache) {
34 | const [thumbnailBase64, width, height] = thumbnailCache[cacheKey];
35 | hexo.log.debug(`Thumbnail loaded from cache: \x1b[35m${cacheKey}\x1b[39m (\x1b[36m${thumbnailBase64.length}\x1b[39m bytes)`);
36 | return {
37 | thumbnailBase64,
38 | width,
39 | height,
40 | };
41 | }
42 |
43 | let input;
44 | if (source.match(/^https?:\/\//)) {
45 | input = Buffer.from(await fetch(source).then(r => {
46 | if (r.status >= 400) throw new Error(`${r.status} ${r.statusText}`);
47 | return r.arrayBuffer();
48 | }));
49 | } else if (hexo.config.post_asset_folder) {
50 | input = path.join(this.asset_dir, source);
51 | } else {
52 | input = path.join(hexo.source_dir, source);
53 | }
54 | const image = sharp(input);
55 | const { width, height, hasAlpha } = await image.metadata();
56 | const thumbnail = image.resize(
57 | width >= height ? Math.min(size, width) : null,
58 | width <= height ? Math.min(size, height) : null,
59 | );
60 | let thumbnailBase64;
61 | if (hasAlpha) {
62 | thumbnailBase64 = 'data:image/png;base64,' + (await thumbnail.png({
63 | palette: true,
64 | quality: 100,
65 | colors: 128,
66 | compressionLevel: 9,
67 | effort: 10,
68 | }).toBuffer()).toString('base64').replace(/=+$/, '');
69 | } else {
70 | thumbnailBase64 = 'data:image/jpeg;base64,' + (await image.jpeg({
71 | quality: 75,
72 | chromaSubsampling: '4:2:0',
73 | quantisationTable: 3,
74 | trellisQuantisation: true,
75 | overshootDeringing: true,
76 | }).toBuffer()).toString('base64').replace(/=+$/, '');
77 | }
78 | thumbnailCache[cacheKey] = [thumbnailBase64, width, height];
79 | hexo.log.debug(`Thumbnail created: \x1b[35m${cacheKey}\x1b[39m (\x1b[36m${thumbnailBase64.length}\x1b[39m bytes)`);
80 | return {
81 | thumbnailBase64,
82 | width,
83 | height,
84 | };
85 | };
86 |
87 | hexo.extend.tag.register(
88 | 'img_blur',
89 | /**
90 | * @param {String[]} args
91 | * @returns {String}
92 | */
93 | async function (args) {
94 | /** @type {Record} */
95 | const sources = {};
96 | /** @type {Record} */
97 | const attrs = {};
98 | for (const [attr, argPrefix] of [
99 | ['data-src-avif', 'avif:'],
100 | ['data-src-webp', 'webp:'],
101 | ['data-src', 'src:'],
102 | ]) {
103 | const index = args.findIndex(e => e.startsWith(argPrefix));
104 | if (index === -1) continue;
105 | sources[attr] = attrs[attr] = args[index].substring(argPrefix.length);
106 | args.splice(index, 1);
107 | }
108 | const [alt, title] = args;
109 | if (alt) attrs.alt = alt;
110 | if (title || alt) attrs.title = title || alt;
111 |
112 | for (const format in sources) {
113 | const source = sources[format];
114 | if (!source || format === 'data-src-avif') continue;
115 |
116 | try {
117 | const { thumbnailBase64, width, height } = await createThumbnail(source, 32);
118 | return `
119 |
120 |
121 |
`${k}="${v}"`).join(' ')}
124 | >
125 |
131 |
139 |
140 | `;
141 | } catch (error) {
142 | hexo.log.warn(`Failed to create thumbnail from \x1b[35m${source}\x1b[39m in \x1b[35m${this.full_source}\x1b[39m (\x1b[31m${error}\x1b[39m)`);
143 | }
144 | }
145 | return `
146 |
`${k}="${v}"`).join(' ')}
149 | >
150 |
158 | `;
159 | },
160 | {
161 | async: true,
162 | },
163 | );
164 |
165 | hexo.extend.filter.register('before_post_render', async data => {
166 | if (data.thumbnail_color) return data;
167 |
168 | for (const source of [
169 | // 'thumbnail_avif',
170 | 'thumbnail_webp',
171 | 'thumbnail',
172 | ]) {
173 | if (!data[source]) continue;
174 | try {
175 | data.thumbnail_color = (await createThumbnail.bind(data)(data[source], 64)).thumbnailBase64;
176 | return data;
177 | } catch (error) {
178 | hexo.log.warn(`Failed to create thumbnail from \x1b[35m${data[source]}\x1b[39m in \x1b[35m${data.full_source}\x1b[39m (\x1b[31m${error}\x1b[39m)`);
179 | }
180 | }
181 | return data;
182 | });
183 |
--------------------------------------------------------------------------------
/source/css/style.css:
--------------------------------------------------------------------------------
1 | /* 导入思源黑体 */
2 | @font-face {
3 | font-family: 'Noto Sans CJK SC';
4 | font-style: normal;
5 | font-weight: 100;
6 | src: local('Noto Sans CJK SC Thin'), local('Source Han Sans SC ExtraLight'), local('Source Han Sans CN ExtraLight');
7 | }
8 | @font-face {
9 | font-family: 'Noto Sans CJK SC';
10 | font-style: normal;
11 | font-weight: 300;
12 | src: local('Noto Sans CJK SC Light'), local('Source Han Sans SC Light'), local('Source Han Sans CN Light');
13 | }
14 | @font-face {
15 | font-family: 'Noto Sans CJK SC';
16 | font-style: normal;
17 | font-weight: 400;
18 | src: local('Noto Sans CJK SC Regular'), local('Source Han Sans SC Regular'), local('Source Han Sans CN Regular');
19 | }
20 | @font-face {
21 | font-family: 'Noto Sans CJK SC';
22 | font-style: normal;
23 | font-weight: 500;
24 | src: local('Noto Sans CJK SC Medium'), local('Source Han Sans SC Medium'), local('Source Han Sans CN Medium');
25 | }
26 | @font-face {
27 | font-family: 'Noto Sans CJK SC';
28 | font-style: normal;
29 | font-weight: 700;
30 | src: local('Noto Sans CJK SC Bold'), local('Source Han Sans SC Bold'), local('Source Han Sans CN Bold');
31 | }
32 | @font-face {
33 | font-family: 'Noto Sans CJK SC';
34 | font-style: normal;
35 | font-weight: 900;
36 | src: local('Noto Sans CJK SC Black'), local('Source Han Sans SC Heavy'), local('Source Han Sans CN Heavy');
37 | }
38 | body {
39 | font-family:
40 | Roboto,
41 | Noto,
42 | "Helvetica Neue",
43 | Helvetica,
44 | "Noto Sans CJK SC",
45 | "PingFang SC",
46 | "Hiragino Sans GB",
47 | "Microsoft YaHei",
48 | "微软雅黑",
49 | Arial,
50 | sans-serif;
51 | }
52 |
53 | /* 抽屉菜单 */
54 | #akarin-drawer-media {
55 | position: relative;
56 | height: 150px;
57 | background-color: var(--sidebar-image-color);
58 | background-image: var(--sidebar-image);
59 | }
60 | #akarin-drawer-avatar {
61 | width: 54px;
62 | height: 54px;
63 | }
64 | .akarin-drawer-badge {
65 | border-radius: 1em;
66 | padding: 2px 6px;
67 | }
68 |
69 | /* 主页大图 */
70 | #akarin-home-banner-wrapper {
71 | padding-top: 150px;
72 | padding-bottom: 200px;
73 | margin-bottom: -150px;
74 | background-color: var(--banner-image-color);
75 | background-image: var(--banner-image);
76 | }
77 | @media (min-width:600px) {
78 | #akarin-home-banner-wrapper {
79 | padding-top: 200px;
80 | padding-bottom: 300px;
81 | margin-bottom: -150px;
82 | }
83 | }
84 | #akarin-home-banner {
85 | max-width: 800px;
86 | display: inline-block;
87 | background-color: rgba(0, 0, 0, .4);
88 | }
89 |
90 | /* 返回顶部 */
91 | picture#akarin-top img,
92 | picture#akarin-top source {
93 | position: fixed;
94 | cursor: pointer;
95 | width: auto;
96 | height: 180px;
97 | bottom: 0;
98 | right: 0;
99 | z-index: 1;
100 | transition: transform ease-out .25s;
101 | transform: translateX(70%);
102 | }
103 | picture#akarin-top img:hover,
104 | picture#akarin-top source:hover {
105 | transform: translateX(0);
106 | }
107 | button#akarin-top {
108 | z-index: 1000;
109 | }
110 |
111 | /* hover头像时的旋转效果 */
112 | .akarin-hover-spin {
113 | transition: transform .4s ease;
114 | }
115 | .akarin-hover-spin:hover {
116 | transform: rotate(360deg);
117 | }
118 |
119 | /* 文章Entry和本体 */
120 | .akarin-post-entry-bg {
121 | min-height: 180px;
122 | position: relative;
123 | background-color: var(--post-thumbnail-color);
124 | }
125 | @media (min-width:600px) {
126 | .akarin-post-entry-bg {
127 | min-height: 210px;
128 | }
129 | }
130 | @media (min-width:1024px) {
131 | .akarin-post-entry-bg {
132 | min-height: 240px;
133 | }
134 | }
135 | .akarin-post-bg {
136 | min-height: 240px;
137 | position: relative;
138 | background-color: var(--post-thumbnail-color);
139 | }
140 | @media (min-width:600px) {
141 | .akarin-post-bg {
142 | min-height: 270px;
143 | }
144 | }
145 | @media (min-width:1024px) {
146 | .akarin-post-bg {
147 | min-height: 300px;
148 | }
149 | }
150 | .akarin-post-title,
151 | .akarin-post-entry-title {
152 | position: absolute;
153 | bottom: 0;
154 | width: 100%;
155 | }
156 |
157 | /* 图片模糊效果 */
158 | .akarin-blurred {
159 | /* The "Blur Up" Technique for Loading Background Images */
160 | /* https://css-tricks.com/the-blur-up-technique-for-loading-background-images/#recreating-the-blur-filter-with-svg */
161 | filter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='$'%3E%3CfeGaussianBlur stdDeviation='9'/%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0,0 1 0 0 0,0 0 1 0 0,0 0 0 9 0'/%3E%3CfeComposite in2='SourceGraphic' operator='in'/%3E%3C/filter%3E%3C/svg%3E#$");
162 | will-change: opacity;
163 | }
164 | .akarin-blurred-fade-out {
165 | transition: opacity 1s;
166 | opacity: 0;
167 | }
168 | .akarin-blurred-container {
169 | position: relative;
170 | }
171 | .akarin-blurred-container > img {
172 | position: absolute;
173 | top: 0;
174 | left: 50%;
175 | height: 100%;
176 | transform: translateX(-50%);
177 | }
178 |
179 | /* 文章内容 */
180 | .akarin-copy-code-btn {
181 | position: absolute;
182 | top: 0;
183 | right: 0;
184 | z-index: 1000;
185 | color: var(--copy-code-btn-color);
186 | }
187 | @media (min-width:600px) {
188 | article.mdui-typo {
189 | font-size: 16px;
190 | }
191 | }
192 | article.mdui-typo pre {
193 | font-size: 1em;
194 | }
195 | article.mdui-typo pre,
196 | article.mdui-typo code,
197 | article.mdui-typo pre code {
198 | line-height: 1.25;
199 | font-family: "Cascadia Mono", "Segoe UI Mono", "Ubuntu Mono", "Roboto Mono", Menlo, Monaco, Consolas, monospace;
200 | }
201 | article.mdui-typo img {
202 | max-height: 480px;
203 | box-shadow:
204 | 0 3px 3px -2px rgba(0, 0, 0, .2),
205 | 0 3px 4px 0 rgba(0, 0, 0, .14),
206 | 0 1px 8px 0 rgba(0, 0, 0, .12);
207 | }
208 | .medium-zoom-image.medium-zoom-image--opened,
209 | .medium-zoom-overlay {
210 | z-index: 10000;
211 | filter: none !important
212 | }
213 | article.mdui-typo img.mdui-hoverable.medium-zoom-image {
214 | transition:
215 | transform .3s cubic-bezier(.2, 0, .2, 1),
216 | box-shadow .25s cubic-bezier(.4, 0, .2, 1)
217 | !important;
218 | }
219 | article.mdui-typo a.headerlink::before {
220 | position: initial;
221 | background-color: transparent;
222 | content: '#';
223 | }
224 | article.mdui-typo a.headerlink {
225 | visibility: hidden;
226 | margin-left: -.65em;
227 | position: absolute;
228 | }
229 | article.mdui-typo h1:hover .headerlink,
230 | article.mdui-typo h2:hover .headerlink,
231 | article.mdui-typo h3:hover .headerlink,
232 | article.mdui-typo h4:hover .headerlink,
233 | article.mdui-typo h5:hover .headerlink,
234 | article.mdui-typo h6:hover .headerlink {
235 | visibility: visible;
236 | }
237 |
238 | /* 其他工具类 */
239 | .akarin-util-bg-cover {
240 | background-position: center;
241 | background-size: cover;
242 | }
243 | .akarin-util-opacity-half {
244 | opacity: .5;
245 | }
246 | .akarin-util-opacity-quarter {
247 | opacity: .75;
248 | }
249 | .akarin-util-text-gradient {
250 | background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, .35), rgba(0, 0, 0, .5))
251 | }
252 | .akarin-util-rounded-5 {
253 | border-radius: 5px;
254 | }
255 | .akarin-util-rounded-7 {
256 | border-radius: 7px;
257 | }
258 | .akarin-util-rounded-9 {
259 | border-radius: 9px;
260 | }
--------------------------------------------------------------------------------
/source/js/medium-zoom.min.js:
--------------------------------------------------------------------------------
1 | /*! medium-zoom 1.0.6 | MIT License | https://github.com/francoischalifour/medium-zoom */
2 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).mediumZoom=t()}(this,(function(){"use strict";var e=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{},c=window.Promise||function(e){function t(){}e(t,t)},u=function(e){var t=e.target;t!==N?-1!==O.indexOf(t)&&w({target:t}):E()},s=function(){if(!A&&T.original){var e=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(k-e)>S.scrollOffset&&setTimeout(E,150)}},f=function(e){var t=e.key||e.keyCode;"Escape"!==t&&"Esc"!==t&&27!==t||E()},p=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t;if(t.background&&(N.style.background=t.background),t.container&&t.container instanceof Object&&(n.container=e({},S.container,t.container)),t.template){var i=o(t.template)?t.template:document.querySelector(t.template);n.template=i}return S=e({},S,n),O.forEach((function(e){e.dispatchEvent(m("medium-zoom:update",{detail:{zoom:j}}))})),j},g=function(){var o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return t(e({},S,o))},v=function(){for(var e=arguments.length,t=Array(e),o=0;o0?t.reduce((function(e,t){return[].concat(e,i(t))}),[]):O;return n.forEach((function(e){e.classList.remove("medium-zoom-image"),e.dispatchEvent(m("medium-zoom:detach",{detail:{zoom:j}}))})),O=O.filter((function(e){return-1===n.indexOf(e)})),j},z=function(e,t){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return O.forEach((function(n){n.addEventListener("medium-zoom:"+e,t,o)})),x.push({type:"medium-zoom:"+e,listener:t,options:o}),j},y=function(e,t){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return O.forEach((function(n){n.removeEventListener("medium-zoom:"+e,t,o)})),x=x.filter((function(o){return!(o.type==="medium-zoom:"+e&&o.listener.toString()===t.toString())})),j},b=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=t.target,r=function(){var t={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},i=void 0,r=void 0;if(S.container)if(S.container instanceof Object)i=(t=e({},t,S.container)).width-t.left-t.right-2*S.margin,r=t.height-t.top-t.bottom-2*S.margin;else{var d=(o(S.container)?S.container:document.querySelector(S.container)).getBoundingClientRect(),m=d.width,a=d.height,l=d.left,c=d.top;t=e({},t,{width:m,height:a,left:l,top:c})}i=i||t.width-2*S.margin,r=r||t.height-2*S.margin;var u=T.zoomedHd||T.original,s=n(u)?i:u.naturalWidth||i,f=n(u)?r:u.naturalHeight||r,p=u.getBoundingClientRect(),g=p.top,v=p.left,h=p.width,z=p.height,y=Math.min(s,i)/h,b=Math.min(f,r)/z,E=Math.min(y,b),w="scale("+E+") translate3d("+((i-h)/2-v+S.margin+t.left)/E+"px, "+((r-z)/2-g+S.margin+t.top)/E+"px, 0)";T.zoomed.style.transform=w,T.zoomedHd&&(T.zoomedHd.style.transform=w)};return new c((function(e){if(i&&-1===O.indexOf(i))e(j);else{if(T.zoomed)e(j);else{if(i)T.original=i;else{if(!(O.length>0))return void e(j);var t=O;T.original=t[0]}if(T.original.dispatchEvent(m("medium-zoom:open",{detail:{zoom:j}})),k=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,A=!0,T.zoomed=d(T.original),document.body.appendChild(N),S.template){var n=o(S.template)?S.template:document.querySelector(S.template);T.template=document.createElement("div"),T.template.appendChild(n.content.cloneNode(!0)),document.body.appendChild(T.template)}if(document.body.appendChild(T.zoomed),window.requestAnimationFrame((function(){document.body.classList.add("medium-zoom--opened")})),T.original.classList.add("medium-zoom-image--hidden"),T.zoomed.classList.add("medium-zoom-image--opened"),T.zoomed.addEventListener("click",E),T.zoomed.addEventListener("transitionend",(function t(){A=!1,T.zoomed.removeEventListener("transitionend",t),T.original.dispatchEvent(m("medium-zoom:opened",{detail:{zoom:j}})),e(j)})),T.original.getAttribute("data-zoom-src")){T.zoomedHd=T.zoomed.cloneNode(),T.zoomedHd.removeAttribute("srcset"),T.zoomedHd.removeAttribute("sizes"),T.zoomedHd.src=T.zoomed.getAttribute("data-zoom-src"),T.zoomedHd.onerror=function(){clearInterval(a),console.warn("Unable to reach the zoom image target "+T.zoomedHd.src),T.zoomedHd=null,r()};var a=setInterval((function(){T.zoomedHd.complete&&(clearInterval(a),T.zoomedHd.classList.add("medium-zoom-image--opened"),T.zoomedHd.addEventListener("click",E),document.body.appendChild(T.zoomedHd),r())}),10)}else if(T.original.hasAttribute("srcset")){T.zoomedHd=T.zoomed.cloneNode(),T.zoomedHd.removeAttribute("sizes"),T.zoomedHd.removeAttribute("loading");var l=T.zoomedHd.addEventListener("load",(function(){T.zoomedHd.removeEventListener("load",l),T.zoomedHd.classList.add("medium-zoom-image--opened"),T.zoomedHd.addEventListener("click",E),document.body.appendChild(T.zoomedHd),r()}))}else r()}}}))},E=function(){return new c((function(e){if(!A&&T.original){A=!0,document.body.classList.remove("medium-zoom--opened"),T.zoomed.style.transform="",T.zoomedHd&&(T.zoomedHd.style.transform=""),T.template&&(T.template.style.transition="opacity 150ms",T.template.style.opacity=0),T.original.dispatchEvent(m("medium-zoom:close",{detail:{zoom:j}})),T.zoomed.addEventListener("transitionend",(function t(){T.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(T.zoomed),T.zoomedHd&&document.body.removeChild(T.zoomedHd),document.body.removeChild(N),T.zoomed.classList.remove("medium-zoom-image--opened"),T.template&&document.body.removeChild(T.template),A=!1,T.zoomed.removeEventListener("transitionend",t),T.original.dispatchEvent(m("medium-zoom:closed",{detail:{zoom:j}})),T.original=null,T.zoomed=null,T.zoomedHd=null,T.template=null,e(j)}))}else e(j)}))},w=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.target;return T.original?E():b({target:t})},L=function(){return S},H=function(){return O},C=function(){return T.original},O=[],x=[],A=!1,k=0,S=l,T={original:null,zoomed:null,zoomedHd:null,template:null};"[object Object]"===Object.prototype.toString.call(a)?S=a:(a||"string"==typeof a)&&v(a),S=e({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},S);var N=r(S.background);document.addEventListener("click",u),document.addEventListener("keyup",f),document.addEventListener("scroll",s),window.addEventListener("resize",E);var j={open:b,close:E,toggle:w,update:p,clone:g,attach:v,detach:h,on:z,off:y,getOptions:L,getImages:H,getZoomedImage:C};return j}}));
3 |
--------------------------------------------------------------------------------
/source/js/script.js:
--------------------------------------------------------------------------------
1 | (document => {
2 |
3 | /**
4 | * @param {String} label
5 | * @param {String} message
6 | * @param {String} color
7 | */
8 | const consoleBadge = (label, message, color) => console.log(
9 | `%c ${label} %c ${message} `,
10 | 'color:#fff;background-color:#555;border-radius:3px 0 0 3px',
11 | `color:#fff;background-color:${color};border-radius:0 3px 3px 0`,
12 | );
13 |
14 | consoleBadge('Project', 'hexo-theme-akarin', '#07c');
15 | consoleBadge('Author', 'TransparentLC', '#f84');
16 | consoleBadge('Source', 'https://github.com/TransparentLC/hexo-theme-akarin', '#4b1');
17 |
18 | // ****************
19 | // 懒加载组件
20 | // ****************
21 | (() => {
22 |
23 | class LazyLoad {
24 | /** @type {{type: String, img: String, mask: Number}[]} */
25 | imageSupportTest = Object.freeze([
26 | Object.freeze({
27 | type: 'webp',
28 | img: 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA',
29 | mask: 1 << 0,
30 | }),
31 | Object.freeze({
32 | type: 'avif',
33 | img: 'data:image/avif;base64,AAAAHGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZgAAAOltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABwaWN0AAAAAAAAAAAAAAAAAAAAAA5waXRtAAAAAAABAAAAHmlsb2MAAAAARAAAAQABAAAAAQAAAQ0AAAAVAAAAKGlpbmYAAAAAAAEAAAAaaW5mZQIAAAAAAQAAYXYwMUNvbG9yAAAAAGhpcHJwAAAASWlwY28AAAAUaXNwZQAAAAAAAAABAAAAAQAAAA5waXhpAAAAAAEIAAAADGF2MUOBABwAAAAAE2NvbHJuY2x4AAEADQAGgAAAABdpcG1hAAAAAAAAAAEAAQQBAoMEAAAAHW1kYXQSAAoHGAAOWAhoNTIIH/AAAQACH0A',
34 | mask: 1 << 1,
35 | }),
36 | Object.freeze({
37 | type: 'jxl',
38 | img: 'data:image/jxl;base64,/wr6HwGRCAYBACQAS4oLFgATIAkn',
39 | mask: 1 << 2,
40 | }),
41 | ])
42 | defaults = Object.freeze({
43 | root: null,
44 | rootMargin: '0px',
45 | threshold: 0,
46 | loadingSrc: null,
47 | beforeObserve: () => {},
48 | afterObserve: () => {},
49 | })
50 |
51 | /**
52 | * @param {HTMLElement[]} image
53 | * @param {{
54 | * root: HTMLElement,
55 | * rootMargin: String,
56 | * threshold: Number | Number[],
57 | * loadingSrc: String,
58 | * beforeObserve: (e: HTMLElement) => void,
59 | * afterObserve: (e: HTMLElement) => void,
60 | * }} config
61 | */
62 | constructor(image, config) {
63 | this.config = {...this.defaults, ...config};
64 | this.imageSupport = 0;
65 | this.observer = new IntersectionObserver(entries => entries.forEach(entry => entry.isIntersecting && this.load(entry.target)), this.config);
66 | Promise.all(
67 | this.imageSupportTest.map(e => new Promise(resolve => {
68 | const testImg = new Image;
69 | testImg.onload = testImg.onerror = () => resolve(testImg.width && e.mask);
70 | testImg.src = e.img;
71 | }))
72 | ).then(result => {
73 | result.forEach(e => this.imageSupport |= e);
74 | consoleBadge(
75 | 'Next-Gen Image',
76 | this.imageSupportTest
77 | .map(e => this.imageSupport & e.mask ? e.type : '')
78 | .filter(e => e)
79 | .join() || 'None',
80 | '#f6b'
81 | );
82 | image.forEach((/** @type {HTMLElement} */ el) => {
83 | (
84 | this.config.loadingSrc ? this.setSrc(el, this.config.loadingSrc) : Promise.resolve()
85 | ).then(() => {
86 | this.config.beforeObserve(el);
87 | this.observer.observe(el);
88 | });
89 | });
90 | });
91 | }
92 | /**
93 | * @param {HTMLElement} el
94 | * @param {String} src
95 | * @returns {Promise}
96 | */
97 | setSrc(el, src) {
98 | return new Promise(resolve => {
99 | const preloadImg = new Image;
100 | preloadImg.onload = preloadImg.onerror = () => {
101 | if (el.tagName.toLowerCase() === 'img') {
102 | el.src = src;
103 | } else {
104 | el.style.backgroundImage = `url(${src})`;
105 | }
106 | resolve();
107 | }
108 | preloadImg.src = src;
109 | });
110 | }
111 | /**
112 | * @param {HTMLElement} el
113 | */
114 | load(el) {
115 | let src = '';
116 | this.imageSupportTest.forEach(e => {
117 | const dataSrc = el.getAttribute(`data-src-${e.type}`);
118 | if (dataSrc && (this.imageSupport & e.mask)) src = dataSrc;
119 | });
120 | this.setSrc(el, src || el.getAttribute('data-src')).then(() => {
121 | this.observer.unobserve(el);
122 | this.config.afterObserve(el);
123 | });
124 | }
125 | destroy() {
126 | this.observer.disconnect();
127 | this.config = null;
128 | }
129 | }
130 |
131 | new LazyLoad(Array.from(document.querySelectorAll('[data-src]')), {
132 | beforeObserve: el => (el.tagName.toLowerCase() === 'img') ? mediumZoom(el, {
133 | margin: 16,
134 | scrollOffset: 8,
135 | background: 'rgba(0,0,0,.85)',
136 | }) : null,
137 | afterObserve: el => {
138 | const blurred = (el.nextElementSibling && el.nextElementSibling.classList.contains('akarin-blurred'))
139 | ? el.nextElementSibling
140 | : el.querySelector('.akarin-blurred');
141 | if (blurred) {
142 | setTimeout(() => blurred.classList.add('akarin-blurred-fade-out'), 50);
143 | setTimeout(() => blurred.style.visibility = 'hidden', 1050);
144 | }
145 | }
146 | });
147 |
148 | })();
149 |
150 | // ****************
151 | // 返回顶部
152 | // ****************
153 | (() => {
154 |
155 | const top = document.getElementById('akarin-top');
156 | if (!top) return;
157 |
158 | const body = document.body;
159 | const documentElement = document.documentElement;
160 |
161 | const scroll = () => {
162 | const bodyScrollTop = body.scrollTop;
163 | const documentScrollTop = documentElement.scrollTop;
164 | const topOffset = bodyScrollTop + documentScrollTop;
165 | const speed = topOffset / 4;
166 | if (bodyScrollTop != 0) {
167 | body.scrollTop -= speed;
168 | } else {
169 | documentElement.scrollTop -= speed;
170 | }
171 | if (topOffset) requestAnimationFrame(scroll);
172 | };
173 |
174 | top.onclick = () => requestAnimationFrame(scroll);
175 |
176 | if (top.tagName.toLowerCase() === 'button') {
177 | const showFab = () => top.classList[
178 | (2 * documentElement.scrollTop < documentElement.clientHeight) ? 'add' : 'remove'
179 | ]('mdui-fab-hide');
180 | let timer;
181 | addEventListener('scroll', () => {
182 | clearInterval(timer);
183 | timer = setTimeout(showFab, 200);
184 | });
185 | showFab();
186 | }
187 |
188 | })();
189 |
190 | // ****************
191 | // 深色模式
192 | // ****************
193 | (() => {
194 |
195 | const dark = Array.from(document.querySelectorAll('[data-dark]'));
196 | dark.forEach((e, i) => {
197 | e.addEventListener('click', () => {
198 | dark.forEach((t, j) => t.classList[(i === j) ? 'add' : 'remove']('mdui-list-item-active'));
199 | switchDark(e.getAttribute('data-dark'));
200 | });
201 | });
202 | const currentMode = localStorage.getItem('dark');
203 | const currentDark = dark.find(e => e.getAttribute('data-dark') === currentMode);
204 | if (currentDark) currentDark.classList.add('mdui-list-item-active');
205 |
206 | })();
207 |
208 | // ****************
209 | // 对文章进行处理
210 | // ****************
211 | (() => {
212 |
213 | // 点击主页的封面图也能打开文章,并且添加预加载
214 | Array.from(document.querySelectorAll('[data-entry]')).forEach(e => {
215 | const el = e.parentElement.previousElementSibling;
216 | el.onclick = () => location.href = e.href;
217 | if (window.preload) el.addEventListener('mouseover', () => !_preloadedList.has(e.href) && setTimeout(() => preload(e.href), 8 * _delayOnHover));
218 | });
219 |
220 | const article = document.querySelector('article');
221 | if (!article) return;
222 |
223 | // 在视频上添加class
224 | Array.from(article.querySelectorAll('video,.video-container')).forEach(e => {
225 | e.classList.add(
226 | `mdui-video-${e.tagName.toLowerCase() === 'video' ? 'fluid' : 'container'}`,
227 | 'mdui-img-rounded',
228 | 'mdui-center',
229 | 'mdui-hoverable'
230 | );
231 | });
232 |
233 | // “复制代码”按钮
234 | const copyBtn = document.createElement('button');
235 | copyBtn.innerHTML = 'content_copy';
236 | copyBtn.classList.add(
237 | 'mdui-btn',
238 | 'mdui-btn-icon',
239 | 'mdui-btn-dense',
240 | 'mdui-ripple',
241 | 'mdui-m-a-1',
242 | 'akarin-copy-code-btn'
243 | );
244 | const copyCode = code => {
245 | const range = document.createRange();
246 | range.selectNodeContents(code);
247 | const selection = document.getSelection();
248 | selection.removeAllRanges();
249 | selection.addRange(range);
250 | document.execCommand('Copy');
251 | selection.removeAllRanges();
252 | mdui.snackbar('代码已复制', { timeout: 2000 });
253 | };
254 | Array.from(article.querySelectorAll('pre[class^="language-"],pre[class*=" language-"]')).forEach(e => {
255 | const btn = copyBtn.cloneNode(true);
256 | btn.onclick = () => copyCode(e.querySelector('code'));
257 | e.insertAdjacentElement('afterbegin', btn);
258 | });
259 |
260 | // 在img上添加一些class
261 | Array.from(document.querySelectorAll('article > img')).forEach(e => {
262 | e.classList.add(
263 | 'mdui-img-fluid',
264 | 'mdui-img-rounded',
265 | 'mdui-center',
266 | 'mdui-hoverable',
267 | 'mdui-m-y-3'
268 | );
269 | });
270 |
271 | })();
272 |
273 | })(document)
--------------------------------------------------------------------------------
/source/css/APlayer.min.css:
--------------------------------------------------------------------------------
1 | .aplayer{background:#fff;font-family:Arial,Helvetica,sans-serif;margin:5px;box-shadow:0 2px 2px 0 rgba(0,0,0,.07),0 1px 5px 0 rgba(0,0,0,.1);border-radius:2px;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal;position:relative}.aplayer *{box-sizing:content-box}.aplayer svg{width:100%;height:100%}.aplayer svg circle,.aplayer svg path{fill:#fff}.aplayer.aplayer-withlist .aplayer-info{border-bottom:1px solid #e9e9e9}.aplayer.aplayer-withlist .aplayer-list{display:block}.aplayer.aplayer-withlist .aplayer-icon-order,.aplayer.aplayer-withlist .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu{display:inline}.aplayer.aplayer-withlrc .aplayer-pic{height:90px;width:90px}.aplayer.aplayer-withlrc .aplayer-info{margin-left:90px;height:90px;padding:10px 7px 0}.aplayer.aplayer-withlrc .aplayer-lrc{display:block}.aplayer.aplayer-narrow{width:66px}.aplayer.aplayer-narrow .aplayer-info,.aplayer.aplayer-narrow .aplayer-list{display:none}.aplayer.aplayer-narrow .aplayer-body,.aplayer.aplayer-narrow .aplayer-pic{height:66px;width:66px}.aplayer.aplayer-fixed{position:fixed;bottom:0;left:0;right:0;margin:0;z-index:99;overflow:visible;max-width:400px;box-shadow:none}.aplayer.aplayer-fixed .aplayer-list{margin-bottom:65px;border:1px solid #eee;border-bottom:none}.aplayer.aplayer-fixed .aplayer-body{position:fixed;bottom:0;left:0;right:0;margin:0;z-index:99;background:#fff;padding-right:18px;transition:all .3s ease;max-width:400px}.aplayer.aplayer-fixed .aplayer-lrc{display:block;position:fixed;bottom:10px;left:0;right:0;margin:0;z-index:98;pointer-events:none;text-shadow:-1px -1px 0 #fff}.aplayer.aplayer-fixed .aplayer-lrc:after,.aplayer.aplayer-fixed .aplayer-lrc:before{display:none}.aplayer.aplayer-fixed .aplayer-info{-webkit-transform:scaleX(1);transform:scaleX(1);-webkit-transform-origin:0 0;transform-origin:0 0;transition:all .3s ease;border-bottom:none;border-top:1px solid #e9e9e9}.aplayer.aplayer-fixed .aplayer-info .aplayer-music{width:calc(100% - 105px)}.aplayer.aplayer-fixed .aplayer-miniswitcher{display:block}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-info{display:block;-webkit-transform:scaleX(0);transform:scaleX(0)}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body{width:66px!important}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-miniswitcher .aplayer-icon{-webkit-transform:rotateY(0);transform:rotateY(0)}.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-lrc,.aplayer.aplayer-fixed .aplayer-icon-play{display:inline-block}.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-menu,.aplayer.aplayer-fixed .aplayer-icon-play{position:absolute;bottom:27px;width:20px;height:20px}.aplayer.aplayer-fixed .aplayer-icon-back{right:75px}.aplayer.aplayer-fixed .aplayer-icon-play{right:50px}.aplayer.aplayer-fixed .aplayer-icon-forward{right:25px}.aplayer.aplayer-fixed .aplayer-icon-menu{right:0}.aplayer.aplayer-arrow .aplayer-icon-loop,.aplayer.aplayer-arrow .aplayer-icon-order,.aplayer.aplayer-mobile .aplayer-icon-volume-down{display:none}.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-loading-icon{display:block}.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.aplayer .aplayer-body{position:relative}.aplayer .aplayer-icon{width:15px;height:15px;border:none;background-color:transparent;outline:none;cursor:pointer;opacity:.8;vertical-align:middle;padding:0;font-size:12px;margin:0;display:inline-block}.aplayer .aplayer-icon path{transition:all .2s ease-in-out}.aplayer .aplayer-icon-back,.aplayer .aplayer-icon-forward,.aplayer .aplayer-icon-lrc,.aplayer .aplayer-icon-order,.aplayer .aplayer-icon-play{display:none}.aplayer .aplayer-icon-lrc-inactivity svg{opacity:.4}.aplayer .aplayer-icon-forward{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.aplayer .aplayer-lrc-content{display:none}.aplayer .aplayer-pic{position:relative;float:left;height:66px;width:66px;background-size:cover;background-position:50%;transition:all .3s ease;cursor:pointer}.aplayer .aplayer-pic:hover .aplayer-button{opacity:1}.aplayer .aplayer-pic .aplayer-button{position:absolute;border-radius:50%;opacity:.8;text-shadow:0 1px 1px rgba(0,0,0,.2);box-shadow:0 1px 1px rgba(0,0,0,.2);background:rgba(0,0,0,.2);transition:all .1s ease}.aplayer .aplayer-pic .aplayer-button path{fill:#fff}.aplayer .aplayer-pic .aplayer-hide{display:none}.aplayer .aplayer-pic .aplayer-play{width:26px;height:26px;border:2px solid #fff;bottom:50%;right:50%;margin:0 -15px -15px 0}.aplayer .aplayer-pic .aplayer-play svg{position:absolute;top:3px;left:4px;height:20px;width:20px}.aplayer .aplayer-pic .aplayer-pause{width:16px;height:16px;border:2px solid #fff;bottom:4px;right:4px}.aplayer .aplayer-pic .aplayer-pause svg{position:absolute;top:2px;left:2px;height:12px;width:12px}.aplayer .aplayer-info{margin-left:66px;padding:14px 7px 0 10px;height:66px;box-sizing:border-box}.aplayer .aplayer-info .aplayer-music{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin:0 0 13px 5px;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;cursor:default;padding-bottom:2px;height:20px}.aplayer .aplayer-info .aplayer-music .aplayer-title{font-size:14px}.aplayer .aplayer-info .aplayer-music .aplayer-author{font-size:12px;color:#666}.aplayer .aplayer-info .aplayer-controller{position:relative;display:flex}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap{margin:0 0 0 5px;padding:4px 0;cursor:pointer!important;flex:1}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap:hover .aplayer-bar .aplayer-played .aplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar{position:relative;height:2px;width:100%;background:#cdcdcd}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded{position:absolute;left:0;top:0;bottom:0;background:#aaa;height:2px;transition:all .5s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played{position:absolute;left:0;top:0;bottom:0;height:2px}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb{position:absolute;top:0;right:5px;margin-top:-4px;margin-right:-10px;height:10px;width:10px;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;-webkit-transform:scale(0);transform:scale(0)}.aplayer .aplayer-info .aplayer-controller .aplayer-time{position:relative;right:0;bottom:4px;height:17px;color:#999;font-size:11px;padding-left:7px}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-time-inner{vertical-align:middle}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon{cursor:pointer;transition:all .2s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon path{fill:#666}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-loop{margin-right:2px}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon:hover path{fill:#000}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-mode{display:none}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap{position:relative;display:inline-block;margin-left:3px;cursor:pointer!important}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap:hover .aplayer-volume-bar-wrap{height:40px}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap{position:absolute;bottom:15px;right:-3px;width:25px;height:0;z-index:99;overflow:hidden;transition:all .2s ease-in-out}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap.aplayer-volume-bar-wrap-active{height:40px}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar{position:absolute;bottom:0;right:10px;width:5px;height:35px;background:#aaa;border-radius:2.5px;overflow:hidden}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume{position:absolute;bottom:0;right:0;width:5px;transition:all .1s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon{display:none}.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon svg{position:absolute;-webkit-animation:rotate 1s linear infinite;animation:rotate 1s linear infinite}.aplayer .aplayer-lrc{display:none;position:relative;height:30px;text-align:center;overflow:hidden;margin:-10px 0 7px}.aplayer .aplayer-lrc:before{top:0;height:10%;background:linear-gradient(180deg,#fff 0,hsla(0,0%,100%,0));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffffff",endColorstr="#00ffffff",GradientType=0)}.aplayer .aplayer-lrc:after,.aplayer .aplayer-lrc:before{position:absolute;z-index:1;display:block;overflow:hidden;width:100%;content:" "}.aplayer .aplayer-lrc:after{bottom:0;height:33%;background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,hsla(0,0%,100%,.8));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffffff",endColorstr="#ccffffff",GradientType=0)}.aplayer .aplayer-lrc p{font-size:12px;color:#666;line-height:16px!important;height:16px!important;padding:0!important;margin:0!important;transition:all .5s ease-out;opacity:.4;overflow:hidden}.aplayer .aplayer-lrc p.aplayer-lrc-current{opacity:1;overflow:visible;height:auto!important;min-height:16px}.aplayer .aplayer-lrc.aplayer-lrc-hide{display:none}.aplayer .aplayer-lrc .aplayer-lrc-contents{width:100%;transition:all .5s ease-out;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;cursor:default}.aplayer .aplayer-list{overflow:auto;transition:all .5s ease;will-change:height;display:none;overflow:hidden}.aplayer .aplayer-list.aplayer-list-hide{max-height:0!important}.aplayer .aplayer-list ol{list-style-type:none;margin:0;padding:0;overflow-y:auto}.aplayer .aplayer-list ol::-webkit-scrollbar{width:5px}.aplayer .aplayer-list ol::-webkit-scrollbar-thumb{border-radius:3px;background-color:#eee}.aplayer .aplayer-list ol::-webkit-scrollbar-thumb:hover{background-color:#ccc}.aplayer .aplayer-list ol li{position:relative;height:32px;line-height:32px;padding:0 15px;font-size:12px;border-top:1px solid #e9e9e9;cursor:pointer;transition:all .2s ease;overflow:hidden;margin:0}.aplayer .aplayer-list ol li:first-child{border-top:none}.aplayer .aplayer-list ol li:hover{background:#efefef}.aplayer .aplayer-list ol li.aplayer-list-light{background:#e9e9e9}.aplayer .aplayer-list ol li.aplayer-list-light .aplayer-list-cur{display:inline-block}.aplayer .aplayer-list ol li .aplayer-list-cur{display:none;width:3px;height:22px;position:absolute;left:0;top:5px;cursor:pointer}.aplayer .aplayer-list ol li .aplayer-list-index{color:#666;margin-right:12px;cursor:pointer}.aplayer .aplayer-list ol li .aplayer-list-author{color:#666;float:right;cursor:pointer}.aplayer .aplayer-notice{opacity:0;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-size:12px;border-radius:4px;padding:5px 10px;transition:all .3s ease-in-out;overflow:hidden;color:#fff;pointer-events:none;background-color:#f4f4f5;color:#909399}.aplayer .aplayer-miniswitcher{display:none;position:absolute;top:0;right:0;bottom:0;height:100%;background:#e6e6e6;width:18px;border-radius:0 2px 2px 0}.aplayer .aplayer-miniswitcher .aplayer-icon{height:100%;width:100%;-webkit-transform:rotateY(180deg);transform:rotateY(180deg);transition:all .3s ease}.aplayer .aplayer-miniswitcher .aplayer-icon path{fill:#666}.aplayer .aplayer-miniswitcher .aplayer-icon:hover path{fill:#000}@-webkit-keyframes aplayer-roll{0%{left:0}to{left:-100%}}@keyframes aplayer-roll{0%{left:0}to{left:-100%}}@-webkit-keyframes rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}
2 |
3 | /*# sourceMappingURL=APlayer.min.css.map*/
--------------------------------------------------------------------------------
/source/fonts/roboto/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hexo-theme-akarin
2 |
3 | 基于 [MDUI](https://www.mdui.org/) 制作,借鉴了 [hexo-theme-material](https://github.com/bolnh/hexo-theme-material) 的样式的自制 Material Design 风格主题。
4 |
5 | 演示:https://akarin.dev
6 |
7 | 这个主题不支持 Internet Explorer。
8 |
9 | ## 主题设置
10 |
11 | > 以下的“网站配置”指的是 Hexo 博客目录下的 `_config.yml`,“主题配置”指的是 `theme/hexo-theme-akarin` 目录下的 `_config.yml`(也可以将这一文件以 `_config.hexo-theme-akarin.yml` 的名称放在 Hexo 博客目录)。
12 |
13 | 安装 Node.js 18 和 [Hexo 6](https://hexo.io/zh-cn/docs/#%E5%AE%89%E8%A3%85)(或以上版本)并成功[建站](https://hexo.io/zh-cn/docs/setup)后,将主题下载到 `theme/hexo-theme-akarin` 目录,执行 `npm install` 安装依赖,然后在网站配置中修改 `theme: hexo-theme-akarin` 即可启用主题。
14 |
15 | 仅支持使用 Hexo 5 添加的 [PrismJS](https://hexo.io/zh-cn/docs/syntax-highlight.html#PrismJS) 进行代码高亮,未支持 Highlight.js。
16 |
17 | ### 导航菜单
18 |
19 | ``` yaml
20 | drawer:
21 | caption:
22 | menu:
23 | 主页:
24 | href: /
25 | icon: home
26 | 关于:
27 | href: /about
28 | icon: person
29 | divider: true
30 | 深色模式:
31 | preset: dark
32 | ```
33 |
34 | | 参数 | 描述 | 默认值 |
35 | | --- | --- | --- |
36 | | `caption` | 在菜单上方显示的博客介绍 | 网站配置的 `title` |
37 | | `menu` | 菜单中的项目,显示的文本为每一项的 key | |
38 | | `menu.key.preset` | 预设的菜单项目,设置了这一项就不需要设置 `href` 和 `icon` | |
39 | | `menu.key.href` | 指向的链接 | |
40 | | `menu.key.icon` | 图标,可以在[这里](https://www.mdui.org/docs/material_icon)选择 | |
41 | | `menu.key.divider` | 在项目下方添加一条分割线 | `false` |
42 |
43 | 使用 `preset` 可以设置的预设项目:
44 | * `archive`:点击后跳转到归档页面 `/archive`,并在右侧显示文章总数
45 | * `rss`:点击后跳转到主题设置里设定的 RSS 链接
46 | * `dark`:是否启用深色模式的设置,可以设为固定启用/禁用/根据系统主题切换
47 | * `stats_busuanzi`:不算子的访问量统计,支持设置是否显示网站 PV/UV 和网页 PV,参见“访问量统计”部分
48 |
49 | ### `` 部分
50 |
51 | ```yaml
52 | head:
53 | favicon: /img/favicon.png
54 | high_res_favicon: /img/favicon.png
55 | apple_touch_icon: /img/favicon.png
56 | keywords:
57 | structured_data: true
58 | site_verification:
59 | google:
60 | baidu:
61 | ```
62 |
63 | | 参数 | 描述 | 默认值 |
64 | | --- | --- | --- |
65 | | `favicon` | 网站的 favicon | |
66 | | `high_res_favicon` | 高清 favicon | |
67 | | `apple_touch_icon` | iOS 主屏按钮图标,对应 `` | |
68 | | `keywords` | 网站关键词,对应 `` | |
69 | | `structured_data` | 生成[结构化数据](https://developers.google.com/search/docs/guides/intro-structured-data) | `false` |
70 | | `site_verification` | 搜索引擎验证,对应 ``,支持 Google 和百度 | |
71 |
72 | ### 页脚
73 |
74 | ```yaml
75 | footer:
76 | since: 2019
77 | text: Hosted by Github Pages
78 | ```
79 |
80 | | 参数 | 描述 | 默认值 |
81 | | --- | --- | --- |
82 | | `since` | 网站建立的年份,显示为 `© 2019 - 2020`,留空则只显示当前年份 | |
83 | | `text` | 页脚显示的文字,可以用来显示备案号等信息,支持使用 HTML | |
84 |
85 | ### 界面设置
86 |
87 | ```yaml
88 | uiux:
89 | slogan: This is a slogan.
90 | sidebar_image: https://picsum.photos/600/400.jpg?blur=10
91 | sidebar_image_webp: https://picsum.photos/600/400.webp?blur=10
92 | sidebar_image_avif:
93 | sidebar_image_color: '#e16b8c'
94 | banner_image: https://picsum.photos/1200/500.jpg
95 | banner_image_webp: https://picsum.photos/1200/500.webp
96 | banner_image_avif:
97 | banner_image_color: '#e16b8c'
98 | mdui_primary_theme: pink
99 | mdui_accent_theme: pink
100 | post_thumbnail_color: '#03a9f4'
101 | copy_code_button_color: '#fff'
102 | top:
103 | enable: true
104 | style: fab
105 | ```
106 |
107 | | 参数 | 描述 | 默认值 |
108 | | --- | --- | --- |
109 | | `slogan` | 显示在主页顶部的标语,可以使用数组设定多行标语 | |
110 | | `avatar` | 头像的 URL | |
111 | | `sidebar_image` | 导航菜单顶部的背景图 URL | |
112 | | `sidebar_image_webp` | WebP 格式的导航菜单顶部的背景图 URL | |
113 | | `sidebar_image_avif` | AVIF 格式的导航菜单顶部的背景图 URL | |
114 | | `sidebar_image_color` | 背景图未加载时显示的颜色,可以使用各种在线小工具提取上面设置的图片的主题色 | |
115 | | `banner_image` | 主页顶部的背景图 URL | |
116 | | `banner_image_webp` | WebP 格式的主页顶部的背景图 URL | |
117 | | `banner_image_avif` | AVIF 格式的主页顶部的背景图 URL | |
118 | | `banner_image_color` | 背景图未加载时显示的颜色 | |
119 | | `mdui_primary_theme` | MDUI 的主题色,参见[这里](https://www.mdui.org/docs/color#color) | |
120 | | `mdui_accent_theme` | MDUI 的强调色 | |
121 | | `post_thumbnail_color` | 文章的封面图未加载时显示的颜色,也可以在每一篇文章的 Front-matter 里单独设定,参见[“Front-matter”](#Front-matter)部分 | |
122 | | `copy_code_button_color` | 文章中“复制代码”按钮的颜色 | |
123 | | `top.enable` | 是否在页面右下角显示“返回顶部”的按钮 | `false` |
124 | | `top.style` | 设为 `fab` 则以浮动操作按钮显示 | |
125 |
126 | ### 文章设置
127 |
128 | ```yaml
129 | posts:
130 | default_excerpt: 120
131 | license: 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
132 | ```
133 |
134 | | 参数 | 描述 | 默认值 |
135 | | --- | --- | --- |
136 | | `default_excerpt` | 没有使用 `` 或在 Front-matter 中设置摘要时,则自动截取文章开头的一定数量的字符作为摘要 | |
137 | | `license` | 文章的版权声明,也可以在 Front-matter 中单独设定,支持使用 HTML | |
138 |
139 | ### 友链
140 |
141 | ```yaml
142 | links:
143 | default_avatar: /img/Transparent_Akkarin.png
144 | description:
145 | list:
146 | Github:
147 | link: https://github.com/
148 | avatar: https://github.githubassets.com/images/modules/open_graph/github-logo.png
149 | description: 全球最大同性交友网站
150 | ```
151 |
152 | | 参数 | 描述 | 默认值 |
153 | | --- | --- | --- |
154 | | `default_avatar` | 友链的默认头像 | |
155 | | `description` | 在友链页面上方显示的内容,可以用来显示友链添加方式等信息,支持使用 HTML | |
156 | | `list` | 友链列表,链接名称为每一项的 key | |
157 | | `list.key.link` | 地址 | |
158 | | `list.key.avatar` | 头像 | `theme.links.default_avatar` |
159 | | `list.key.description` | 链接的介绍 | |
160 |
161 | 要生成友链页面,你需要在网站的 source 文件夹中自定义一个文件夹(例如 friend),然后在这个文件夹里新建 `index.md`,写入以下内容:
162 |
163 | ```
164 | ---
165 | title: 友链页面标题
166 | layout: links
167 | ---
168 | ```
169 |
170 | ### 评论区
171 |
172 | ```yaml
173 | comment:
174 | livere:
175 | enable: false
176 | uid:
177 | artalk:
178 | enable: false
179 | server:
180 | site:
181 | stylesheet:
182 | script:
183 | ```
184 |
185 | | 参数 | 描述 | 默认值 |
186 | | --- | --- | --- |
187 | | `livere.enable` | 是否启用 LiveRe 评论功能 | `false` |
188 | | `livere.uid` | LiveRe 安装代码中的 `data-uid` 的值 | |
189 | | `artalk.enable` | 是否启用 Artalk 评论功能 | `false` |
190 | | `artalk.server` | Artalk 后端地址 | |
191 | | `artalk.site` | 站点名 | `config.title` |
192 | | `artalk.stylesheet` | 从 CDN 引入 Artalk 的 CSS 的地址 | `https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.css` |
193 | | `artalk.script` | 从 CDN 引入 Artalk 的 JS 的地址 | `https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.js` |
194 |
195 | 暂时只支持 [LiveRe](https://livere.com/) 和 [Artalk](https://artalk.js.org)。
196 |
197 | LiveRe 的评论区在启用深色模式的情况下无法正常显示。
198 |
199 | ### 访问统计
200 |
201 | ```yaml
202 | stats:
203 | busuanzi:
204 | enable: false
205 | script: https://cdn.jsdelivr.net/npm/busuanzi
206 | site_uv: true
207 | site_pv: true
208 | page_pv: true
209 | ```
210 |
211 | | 参数 | 描述 | 默认值 |
212 | | --- | --- | --- |
213 | | `busuanzi.enable` | 是否启用不蒜子 | `false` |
214 | | `busuanzi.script` | 加载的 JS | 使用[官方提供的 JS](https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js) |
215 | | `busuanzi.site_uv` | 在导航菜单中的 `preset:stats_busuanzi` 处显示站点访问量 | `false` |
216 | | `busuanzi.site_pv` | 显示站点访客数 | `false` |
217 | | `busuanzi.page_pv` | 显示页面访问量 | `false` |
218 |
219 | 暂时只支持[不蒜子](https://busuanzi.ibruce.info/)。
220 |
221 | ### 其它设置
222 |
223 | ```yaml
224 | rss:
225 | minify:
226 | enable: true
227 | aplayer:
228 | script: /js/APlayer.min.js
229 | stylesheet: /css/APlayer.min.css
230 | stylesheets:
231 | - /css/mdui.min.css
232 | - /css/prism-line-numbers.min.css
233 | - /css/prism-vsc-dark-plus.min.css
234 | - /css/APlayer.min.css
235 | - /css/style.css
236 | scripts:
237 | - /js/mdui.min.js
238 | - /js/medium-zoom.min.js
239 | - /js/APlayer.min.js
240 | - /js/script.js
241 | preconnect:
242 | - https://cdn.jsdelivr.net
243 | dns_prefetch:
244 | - https://example.com
245 | ```
246 |
247 | | 参数 | 描述 | 默认值 |
248 | | --- | --- | --- |
249 | | `rss` | RSS 的路径,留空则导航菜单中的 `preset:rss` 不会显示 | |
250 | | `minify_html` | 对生成的 HTML 进行压缩,参见[“HTML 压缩”](#html-压缩)部分 | |
251 | | `aplayer` | [APlayer](https://github.com/DIYgod/APlayer) 使用的 CSS 和 JS,参见[“APlayer 标签插件”](#aplayer-标签插件)部分 | |
252 | | `stylesheets` | 需要导入的其它 CSS,和 Hexo 的辅助函数 [`css`](https://hexo.io/zh-cn/docs/helpers#css) 相同 | |
253 | | `scripts` | 需要导入的其它 JS,和 Hexo 的辅助函数 [`js`](https://hexo.io/zh-cn/docs/helpers#js) 相同 | |
254 | | `preconnect` | 需要添加 `` 的域名 | |
255 | | `dns_prefetch` | 需要添加 `` 的域名 | |
256 |
257 | * 可以使用插件 [hexo-generator-feed](https://github.com/hexojs/hexo-generator-feed) 生成 RSS
258 | * 至少需要导入以下 CSS:
259 | * [MDUI](https://github.com/zdhxiong/mdui/blob/v1/dist/css/mdui.min.css)
260 | * PrismJS 的任意一个[主题](https://github.com/PrismJS/prism-themes)(如果使用了 PrismJS)
261 | * PrismJS 的[行号显示插件](https://github.com/PrismJS/prism/blob/master/plugins/line-numbers/prism-line-numbers.css)(如果使用了行号显示功能)
262 | * 本主题的 [CSS 文件](https://github.com/TransparentLC/hexo-theme-akarin/blob/master/source/css/style.css)
263 | * 至少需要导入以下 JS:
264 | * [MDUI](https://github.com/zdhxiong/mdui/blob/v1/dist/js/mdui.min.js)
265 | * [medium-zoom](https://github.com/francoischalifour/medium-zoom#installation)
266 | * PrismJS 本体和各个插件,参见 [Hexo 文档](https://hexo.io/zh-cn/docs/syntax-highlight.html#preprocess)(如果使用了浏览器端高亮)
267 | * 本主题的 [JS 文件](https://github.com/TransparentLC/hexo-theme-akarin/blob/master/source/js/script.js)
268 | * 如果对加载速度有更高的要求,可以尝试以下方法:
269 | * 将主题的 CSS 和 JS 文件进行 minify,相关工具:[Terser](https://try.terser.org/)、[swc](https://swc.rs/)、[lightningcss](https://lightningcss.dev/)
270 | * 使用 [jsDelivr](https://www.jsdelivr.com/) 等公共 CDN 服务
271 | * 对于 jsDelivr,可以使用[合并文件](https://www.jsdelivr.com/features#combine)功能,减少网络请求数并提高压缩比,还可以在文件名中加上 `min` 自动 minify
272 | * 下载 MDUI 的源代码,根据主题配置中设定的主题色和强调色(`theme.uiux.mdui_primary/accent_theme`),去除不需要的主题和组件后自行编译 CSS 和 JS,替换主题自带的完整版。可以参考这里修改源代码 src 目录下的对应文件:[index.ts](https://pastebin.com/VZGCd2pf)、[index.less](https://pastebin.com/bLy8SxRM)
273 |
274 | ## Front-matter
275 |
276 | 参见 [Hexo 文档](https://hexo.io/zh-cn/docs/front-matter),主题还额外支持一些 Front-matter:
277 |
278 | | 参数 | 描述 | 默认值 |
279 | | --- | --- | --- |
280 | | `title` | 标题 | 文件名 |
281 | | `date` | 建立日期 | 文件建立日期 |
282 | | `updated` | 更新日期 | 文件更新日期 |
283 | | `tags` | 标签 | |
284 | | `categories` | 分类 | |
285 | | `excerpt` | 摘要 | 从文章的开头一部分截取,长度为 `theme.posts.default_excerpt` |
286 | | `thumbnail` | 封面图 | |
287 | | `thumbnail_webp` | WebP 格式的封面图 | |
288 | | `thumbnail_avif` | AVIF 格式的封面图 | |
289 | | `thumbnail_color` | 封面图未加载时显示的颜色,也可以填入一个图片的 Data URL 或留空以自动生成 | |
290 | | `hide_license` | 不显示版权声明 | `false` |
291 | | `license` | 文章的版权声明 | `theme.posts.license` |
292 | | `comments` | 是否允许评论 | `true` |
293 | | `author` | 作者的名称,替换网站配置中设定的值 | `config.author` |
294 | | `avatar` | 作者的头像,替换网站配置中设定的值 | `config.avatar` |
295 |
296 | 关于封面图相关选项的详细介绍,可以参见下面的[“使用现代图片格式和图片渐进式加载”](#使用现代图片格式和图片渐进式加载)部分。
297 |
298 | ## 各种小功能
299 |
300 | ### APlayer 标签插件
301 |
302 | 内置了简单的 [APlayer](https://github.com/DIYgod/APlayer) 标签插件,可以快速在文章中插入音乐播放器。
303 |
304 | ```plain
305 | {% aplayerlite title author audioURL [coverURL] [lrcURL] %}
306 |
307 | {% aplayerlitelrc title author audioURL [coverURL] %}
308 | [00:00.000] LRC歌词内容
309 | [00:01.000] ……
310 | {% endaplayerlitelrc %}
311 | ```
312 |
313 | 使用例:
314 |
315 | ```plain
316 | {% aplayerlite
317 | "TOKIMEKI Runners"
318 | "虹ヶ咲学園スクールアイドル同好会"
319 | "https://fs-im-kefu.7moor-fs2.com/im/2768a390-5474-11ea-afc9-7b323e3e16c0/lbsgI27N.m4a"
320 | "https://yzf.qq.com/fsnb/kf-file/kf_pic/20220601/KFPIC_Au_WXIMAGE_007732d2a6c24a438413c7ca925d4dd7.jpg"
321 | "https://fs-im-kefu.7moor-fs2.com/im/2768a390-5474-11ea-afc9-7b323e3e16c0/T-2g8Whd.txt"
322 | %}
323 | ```
324 |
325 | 在未启用 JS 的环境下,将使用 HTML 原生 `