├── 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 |

本站推荐你使用 FirefoxMicrosoft 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 | ${text} 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 |
47 |
48 | <%= page.author || config.author %> 的头像 49 |
<%= page.author || config.author %>
50 |
<%= date(page.date, 'YYYY-MM-DD HH:mm:ss') %>
51 |
52 | <% if (page.tags && page.tags.data.length > 0) { %> 53 |
54 |
55 | <% page.tags.data.forEach((tag, i) => { %> 56 | <%= tag.name %> 60 | <% }); %> 61 |
62 | <% } %> 63 |
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 原生 `