diff --git a/README.md b/README.md index ff0173a..7aacdd6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,40 @@ # hexo-theme-stellar + Elegant and powerful theme for Hexo. + +## Getting Started + +Check your environment: + +```yaml +Hexo: 5.3.0 +hexo-cli: 4.2.0 +node.js: 14.15.4 LTS +npm: 6.14.10 LTS +``` + +Edit your `_config.yml`: + +```yaml +theme: stellar +``` + +Install Stellar in terminal: + +```bash +npm i hexo-theme-stellar +``` + +## Usage + +See docs: https://xaoxuu.com/wiki/stellar + +## Examples + +https://xaoxuu.com + +## Feedback + +Issues: https://github.com/xaoxuu/hexo-theme-stellar/issues/ + +Discussions: https://github.com/xaoxuu/hexo-theme-stellar/discussions/ diff --git a/_config.yml b/_config.yml new file mode 100755 index 0000000..ae9afca --- /dev/null +++ b/_config.yml @@ -0,0 +1,164 @@ +######## Stellar info ######## +stellar: + version: '1.0.0-rc.1' + homepage: https://xaoxuu.com/wiki/stellar/ + repo: https://github.com/xaoxuu/hexo-theme-stellar + # The cdn version needs to be consistent with the stellar version + cdn_css: # https://cdn.jsdelivr.net/npm/hexo-theme-stellar@1.0/source/css/main.min.css + cdn_js: # https://cdn.jsdelivr.net/npm/hexo-theme-stellar@1.0/source/js/main.min.js + + +######## head tags ######## +head: + open_graph: true + twitter: false + + +######## Sidebar ######## +sidebar: + logo: + avatar: # default is config.avatar + title: # default is config.title + logo_action: + avatar: /about/ + title: / + menu: + - class: post # post, wiki, about + name: btn.blog + url: / + - class: wiki + name: btn.wiki + url: /wiki/ + - class: friends + name: 友链 + url: /friends/ + - class: about + name: 关于 + url: /about/ + # Sidebar widgets + widgets: + # Recent update + recent: + layout: recent + rss: /atom.xml # npm i hexo-generator-feed + limit: 5 # Count of posts + # TOC (valid only in layout:post/wiki) + toc: + layout: toc + list_number: false + min_depth: 2 + max_depth: 5 + # welcome + welcome: + layout: markdown + title: 欢迎 + content: + - '欢迎光临小站,[Stellar](https://github.com/xaoxuu/hexo-theme-stellar/) 是一个支持 wiki 的 hexo 主题,适合综合型站点使用。同时也拥有简约而精美的视觉设计和丰富的标签插件,帮助您简单从容地应对各种场合。' + + + +######## Article ######## +article: + # 如果没有指定 excerpt 和 description,将自动取多长的内容作为文章摘要? + auto_excerpt: 200 + # 相关文章,需要安装插件 (for layout: post) + # npm i hexo-related-popular-posts + related_posts: + enable: false + title: 您可能感兴趣的文章 + max_count: 5 + placeholder_img: https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/046.jpg + # 分享文章 + share: + qq: https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qq.png + qzone: https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qzone.png + weibo: https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/weibo.png + # 需要安装插件 npm i hexo-helper-qrcode + wechat: https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/wechat.png + + +######## Comments ######## +comments: + service: utterances # utterances + # utterances + # https://utteranc.es/ + utterances: + repo: xxx/xxx + issue-term: pathname + issue-number: + theme: + light: github-light + dark: github-dark + label: ✨💬✨ + crossorigin: anonymous + + +######## Footer ######## +footer: + social: + - icon: '' + url: /atom.xml + - icon: '' + url: https://github.com/xaoxuu + - icon: '' + url: https://music.163.com/#/user/home?id=63035382 + - icon: '' + url: /comments/ + license: 'CC BY SA 4.0' + source: + where: GitHub + url: https://github.com/xaoxuu/site-source + + +######## Tag Plugins ######## +tag_plugins: + # {% note text %} + note: + default_color: '' + # {% checkbox %} + checkbox: + interactive: false # enable interactive for user + # {% link title, url, img %} + link: + default_img: https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/256/safari.png + + +######## JS Plugins ######## +plugins: + ## required plugins ## + # jquery + jquery: https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js + + ## lazyload plugins ## + # fancybox + fancybox: https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css + # swiper + swiper: + enable: true + css: https://unpkg.com/swiper/swiper-bundle.min.css + js: https://unpkg.com/swiper/swiper-bundle.min.js + ## optional plugins ## + # preload + preload: + enable: #true + service: instant_page # instant_page, flying_pages + instant_page: https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@2/js/instant_page.js + flying_pages: https://cdn.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js + + # image lazyload + # https://www.npmjs.com/package/vanilla-lazyload + lazyload: + enable: true + js: https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.3.1/dist/lazyload.min.js + onlypost: false + loadingImg: # https://7.dusays.com/2021/02/14/e45d2469cdeaf.svg + blurIn: true # 模糊加载效果 (loadingImg为空时有效) + + # https://scrollrevealjs.org/api/reveal.html + scrollreveal: + enable: true + js: https://cdn.jsdelivr.net/npm/scrollreveal@4.0.7/dist/scrollreveal.min.js + distance: 16px + duration: 800 # ms + interval: 80 # ms + scale: 1 # 0.1~1 diff --git a/languages/en.yml b/languages/en.yml new file mode 100755 index 0000000..0fddc1d --- /dev/null +++ b/languages/en.yml @@ -0,0 +1,46 @@ +btn: + home: Home + blog: Blog + wiki: Wiki + recent_publish: Recent + all_wiki: All + category: Category + categories: Categories + tag: Tag + tags: Tags + archives: Archives + learn_more: Learn more + getting_started: Getting Started + +meta: + recent_update: Recent Update + toc: TOC + read_prev: PREV + read_next: NEXT + older: Older + newer: Newer + references: References + comment_title: Join the discussion + back_to_top: Back to top + more: 'More %s' + +footer: + license: 'Unless otherwise specified, this site adopts the CC BY SA 4.0 license agreement.' + info_not_open_source: 'This site was created by %s, using [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) as the theme.' + info_open_source: 'This site was created by %s, using [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) as the theme. You can find the source code of this site in [%s](%s).' + +page: + error: + what: Page Not Found + why: The address may be entered incorrectly or the address has been deleted + action: Back to Home + categories: '%s Categories' + tags: '%s Tags' + archives: '%s Years, %s Archives' + +symbol: + comma: ", " + period: ". " + colon: ": " + brackets_l: "(" + brackets_r: ")" diff --git a/languages/zh-CN.yml b/languages/zh-CN.yml new file mode 100755 index 0000000..f26c956 --- /dev/null +++ b/languages/zh-CN.yml @@ -0,0 +1,46 @@ +btn: + home: 主页 + blog: 文章 + wiki: 项目 + recent_publish: 最新发布 + all_wiki: 所有项目 + category: 分类 + categories: 分类 + tag: 标签 + tags: 标签 + archives: 归档 + learn_more: 了解详情 + getting_started: 开始使用 + +meta: + recent_update: 最近更新 + toc: 本文目录 + read_prev: 回顾上一篇 + read_next: 接下来阅读 + older: 较早文章 + newer: 较新文章 + references: 参考资料 + comment_title: 快来参与讨论吧 + back_to_top: 回到顶部 + more: '更多%s' + +footer: + license: '除非特别说明,本站采用 CC BY SA 4.0 许可协议。' + info_not_open_source: '本站由 %s 创建,使用 [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) 作为主题。' + info_open_source: '本站由 %s 创建,使用 [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) 作为主题,您可以在 [%s](%s) 找到本站源码。' + +page: + error: + what: 很抱歉,您访问的页面不存在 + why: 可能是输入地址有误或该地址已被删除 + action: 返回主页 + categories: '共%s个分类' + tags: '共%s个标签' + archives: 'TA在%s年间写了%s篇文章' + +symbol: + comma: "," + period: "。" + colon: ":" + brackets_l: "(" + brackets_r: ")" diff --git a/languages/zh-TW.yml b/languages/zh-TW.yml new file mode 100755 index 0000000..26c1b9a --- /dev/null +++ b/languages/zh-TW.yml @@ -0,0 +1,46 @@ +btn: + home: 主頁 + blog: 博客 + wiki: 項目 + recent_publish: 最新發布 + all_wiki: 所有項目 + category: 分類 + categories: 分類 + tag: 標籤 + tags: 標籤 + archives: 歸檔 + learn_more: 了解詳情 + getting_started: 開始使用 + +meta: + recent_update: 最近更新 + toc: 本文目錄 + read_prev: 回顧上一篇 + read_next: 接下來閱讀 + older: 較早文章 + newer: 較新文章 + references: 參考資料 + comment_title: 快來參與討論吧 + back_to_top: 回到頂部 + more: '更多%s' + +footer: + license: '除非特別說明,本站採用 CC BY SA 4.0 許可協議。' + info_not_open_source: '本站由 %s 創建,使用 [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) 作為主題。' + info_open_source: '本站由 %s 創建,使用 [Stellar](https://github.com/xaoxuu/hexo-theme-stellar) 作為主題,您可以在 [%s](%s) 找到本站源碼。' + +page: + error: + what: 很抱歉,您訪問的頁面不存在 + why: 可能是輸入地址有誤或該地址已被刪除 + action: 返回主頁 + categories: '共%s個分類' + tags: '共%s個標籤' + archives: 'TA在%s年間寫了%s篇文章' + +symbol: + comma: "," + period: "。" + colon: ":" + brackets_l: "(" + brackets_r: ")" diff --git a/layout/404.ejs b/layout/404.ejs new file mode 100755 index 0000000..7f99b93 --- /dev/null +++ b/layout/404.ejs @@ -0,0 +1,19 @@ +<% +page.class = '404'; +page.layout = '404'; +page.comment_title = ''; +page.comment_id = '1'; +%> +
+

+

+ + <%- __('page.error.what') %> + +

+

+ <%- __('page.error.why') %> +

+ <%- __('page.error.action') %> +
+<%- partial('_partial/plugins/comments/layout') %> diff --git a/layout/_partial/article/read_next.ejs b/layout/_partial/article/read_next.ejs new file mode 100644 index 0000000..9a15b78 --- /dev/null +++ b/layout/_partial/article/read_next.ejs @@ -0,0 +1,89 @@ +<% +function layoutDiv() { + var prev,next; + var title = ''; + var title_prev = ''; + var title_next = ''; + if (page.layout == 'post') { + prev = page.prev; + next = page.next; + title = __('meta.read_next'); + title_prev = __('meta.newer'); + title_next = __('meta.older'); + } else if (page.layout == 'wiki' && page.wiki && page.wiki.length > 0) { + title = page.wiki; + title_prev = __('meta.read_prev'); + title_next = __('meta.read_next'); + var wikis = []; + wikis = site.pages.filter(function (p) { + if (p.layout == 'wiki' && p.wiki && p.wiki == page.wiki) { + if (p.order == undefined) { + p.order = 0; + } + return true; + } else { + return false; + } + }).sort('order'); + wikis.forEach((p, i) => { + if (p.order < page.order) { + if (prev == undefined || p.order > prev.order) { + prev = p; + } + } else if (p.order > page.order) { + if (next == undefined || p.order < next.order) { + next = p; + } + } + }); + } + let wrapper = ''; + if (prev || next) { + wrapper += ''; + } + return wrapper; +} +%> +<%- layoutDiv(); %> diff --git a/layout/_partial/article/references.ejs b/layout/_partial/article/references.ejs new file mode 100644 index 0000000..e9ff6f2 --- /dev/null +++ b/layout/_partial/article/references.ejs @@ -0,0 +1,23 @@ +<% +function layoutDiv() { + if (page.references && page.references.length > 0) { + let wrapper = ''; + wrapper += '
'; + wrapper += '
'; + wrapper += '' + __('meta.references') + ''; + wrapper += '
'; + wrapper += '
'; + wrapper += '
'; + return wrapper; + } +} +%> +<%- layoutDiv(); %> diff --git a/layout/_partial/article/related_posts.ejs b/layout/_partial/article/related_posts.ejs new file mode 100644 index 0000000..3b180e5 --- /dev/null +++ b/layout/_partial/article/related_posts.ejs @@ -0,0 +1,5 @@ +<% let post = page; %> + diff --git a/layout/_partial/article/wiki_cover.ejs b/layout/_partial/article/wiki_cover.ejs new file mode 100644 index 0000000..b1fb595 --- /dev/null +++ b/layout/_partial/article/wiki_cover.ejs @@ -0,0 +1,51 @@ +<% +function layoutWikiCover() { + if (page.layout != 'wiki') { + return ''; + } + if (page.cover == undefined || page.cover == false || page.cover == '[]') { + return ''; + } + var cover = page.cover; + if (page.cover == true) { + cover = ['logo', 'title', 'description']; + } + var el = ''; + el += '
'; + el += '
'; + if (page.logo && cover.includes('logo')) { + el += ''; + } + if (page.title && cover.includes('title')) { + el += '
'; + el += '' + (page.wiki || page.title) + ''; + el += '
'; + } + if (page.description && cover.includes('description')) { + el += '
' + page.description + '
'; + } + el += '
'; + el += '' + __('btn.getting_started') + ''; + el += '
'; + el += '
'; + el += '
'; + el += '
'; + return el; +} +%> +<%- layoutWikiCover() %> diff --git a/layout/_partial/footer.ejs b/layout/_partial/footer.ejs new file mode 100755 index 0000000..894dcda --- /dev/null +++ b/layout/_partial/footer.ejs @@ -0,0 +1,18 @@ +<% +function layoutDiv() { + var wrapper = ''; + wrapper += '

'; + if (theme.footer.license) { + wrapper += markdown(__('footer.license', theme.footer.license)); + } + const author = '[' + config.author + '](' + config.url + config.root + ')'; + if (theme.footer.source && theme.footer.source.where && theme.footer.source.url) { + wrapper += markdown(__('footer.info_open_source', author, theme.footer.source.where, theme.footer.source.url)); + } else { + wrapper += markdown(__('footer.info_not_open_source', author)); + } + wrapper += '
'; + return wrapper; +} +%> +<%- layoutDiv() %> \ No newline at end of file diff --git a/layout/_partial/head.ejs b/layout/_partial/head.ejs new file mode 100755 index 0000000..d97de3a --- /dev/null +++ b/layout/_partial/head.ejs @@ -0,0 +1,134 @@ +<% +function genrateRobots() { + var el = ''; + if (page.robots) { + el += ''; + } else if (is_home() == false) { + if (['post', 'wiki', 'index'].includes(page.layout) == false) { + el += ''; + } + } + return el; +} + +function getTitle() { + if (page.seo_title || page.title || page.wiki || page.layout) { + return (page.seo_title || page.title || page.wiki || page.layout) + ' - ' + config.title; + } else if (page.category) { + return __('btn.category') + __('symbol.colon') + page.category + ' - ' + config.title; + } else if (page.tag) { + return __('btn.tag') + __('symbol.colon') + page.tag + ' - ' + config.title; + } else { + return config.title; + } + return ''; +} +function getKeywords() { + if (page.keywords) { + return page.keywords; + } else if (page.tags && page.tags.length > 0) { + return page.tags.map(function(t){return t.name}).join(','); + } + return ''; +} +function getDescription() { + if (page.description) { + return page.description; + } else { + if (['post', 'wiki'].includes(page.layout)) { + if (page.excerpt && page.excerpt.length > 0) { + return strip_html(page.excerpt); + } else if (page.content && page.content.length > 0) { + return truncate(strip_html(page.content), {length: 160}); + } + } + } + return ''; +} +function genrateKeywords() { + const keywords = getKeywords(); + if (keywords && keywords.length > 0) { + return ''; + } else { + return ''; + } +} +function genrateDescription() { + const description = getDescription(); + if (description && description.length > 0) { + return ''; + } else { + return ''; + } +} +function genrateOpenGraph() { + if (theme.head.open_graph == false) { + return ''; + } + var el = ''; + el += ''; + el += ''; + el += ''; + el += ''; + el += ''; + el += ''; + if (page.layout == 'post' && page.cover && page.cover.length > 0) { + el += ''; + } + return el; +} +function genrateTwitter() { + if (theme.head.twitter == undefined || theme.head.twitter.length == 0 || theme.head.twitter == false) { + return ''; + } + var el = ''; + if (theme.head.twitter != 'true') { + el += ''; + } + if (page.layout == 'post' && page.cover && page.cover.length > 0) { + el += ''; + el += ''; + } + return el; +} +%> + + + <%- genrateRobots() %> + + + + + + + + + + + + <%- getTitle() %> + <%- genrateKeywords() %> + <%- genrateDescription() %> + <%- genrateOpenGraph() %> + <%- genrateTwitter() %> + + + + <% if (config.feed && config.feed.path) { %> + <%- feed_tag(config.feed.path, {title: config.title}) %> + <% } %> + + <% if (theme.stellar.cdn_css) { %> + <%- css(theme.stellar.cdn_css) %> + <% } else { %> + <%- css('/css/main.css') %> + <% } %> + + <% if (config.inject && config.inject.head){ %> + <% (config.inject.head||[]).forEach(function(item){ %> + <%- item %> + <% }) %> + <% } else if (config.favicon) { %> + + <% } %> + diff --git a/layout/_partial/menubtn.ejs b/layout/_partial/menubtn.ejs new file mode 100644 index 0000000..dff7a33 --- /dev/null +++ b/layout/_partial/menubtn.ejs @@ -0,0 +1,5 @@ + diff --git a/layout/_partial/navbar/breadcrumb.ejs b/layout/_partial/navbar/breadcrumb.ejs new file mode 100644 index 0000000..6987283 --- /dev/null +++ b/layout/_partial/navbar/breadcrumb.ejs @@ -0,0 +1,47 @@ +<% if (page.breadcrumb != false) { %> + +<% } %> diff --git a/layout/_partial/navbar/list_post.ejs b/layout/_partial/navbar/list_post.ejs new file mode 100644 index 0000000..6a93b1d --- /dev/null +++ b/layout/_partial/navbar/list_post.ejs @@ -0,0 +1,27 @@ + diff --git a/layout/_partial/navbar/list_wiki.ejs b/layout/_partial/navbar/list_wiki.ejs new file mode 100644 index 0000000..d0117d3 --- /dev/null +++ b/layout/_partial/navbar/list_wiki.ejs @@ -0,0 +1,26 @@ + diff --git a/layout/_partial/plugins/comments/layout.ejs b/layout/_partial/plugins/comments/layout.ejs new file mode 100644 index 0000000..94ab05b --- /dev/null +++ b/layout/_partial/plugins/comments/layout.ejs @@ -0,0 +1,27 @@ +<% +var loadComment = false; +if (theme.comments.service && theme.comments.service.length > 0) { + if (page.comments == undefined || page.comments != false) { + loadComment = true; + } +} +// 合并项目评论 +if (loadComment && page.layout == 'wiki' && page.wiki) { + if (page.comment_id == undefined) { + if (theme.comments.service == 'utterances') { + // 使用项目名作为评论issue标题并共享评论数据 + page.comment_id = page.wiki; + } + } +} +%> +<% if (loadComment) { %> +
+
+ <%- page.comment_title != undefined ? page.comment_title : __('meta.comment_title') %> +
+
+ <%- partial(theme.comments.service + '/layout') %> +
+
+<% } %> diff --git a/layout/_partial/plugins/comments/script.ejs b/layout/_partial/plugins/comments/script.ejs new file mode 100644 index 0000000..b22ff7e --- /dev/null +++ b/layout/_partial/plugins/comments/script.ejs @@ -0,0 +1,3 @@ +<% if (theme.comments.service && theme.comments.service.length > 0) { %> + <%- partial(theme.comments.service + '/script') %> +<% } %> diff --git a/layout/_partial/plugins/comments/utterances/layout.ejs b/layout/_partial/plugins/comments/utterances/layout.ejs new file mode 100644 index 0000000..a447688 --- /dev/null +++ b/layout/_partial/plugins/comments/utterances/layout.ejs @@ -0,0 +1 @@ +
diff --git a/layout/_partial/plugins/comments/utterances/script.ejs b/layout/_partial/plugins/comments/utterances/script.ejs new file mode 100644 index 0000000..0ef8582 --- /dev/null +++ b/layout/_partial/plugins/comments/utterances/script.ejs @@ -0,0 +1,29 @@ + diff --git a/layout/_partial/post_list/paginator.ejs b/layout/_partial/post_list/paginator.ejs new file mode 100644 index 0000000..6982cdb --- /dev/null +++ b/layout/_partial/post_list/paginator.ejs @@ -0,0 +1,13 @@ +<% if (is_home() && page.total > 1) { %> +
+ + + +
+ <%- page.current %> / <%- page.total %> +
+ + + +
+<% } %> diff --git a/layout/_partial/post_list/post_card.ejs b/layout/_partial/post_list/post_card.ejs new file mode 100755 index 0000000..7761503 --- /dev/null +++ b/layout/_partial/post_list/post_card.ejs @@ -0,0 +1,59 @@ +<% +let showCat = false; +if (post.categories && post.categories.length > 0) { + showCat = true; +} +%> +<% if (post.cover) { %> +
+ <% if (theme.plugins.lazyload && theme.plugins.lazyload.enable) { %> + <% if (theme.plugins.lazyload.loadingImg) { %> +
+ <% } else { %> +
+ <% } %> + <% } else { %> +
+ <% } %> +
+<% } %> +

+ <%- (post.title || post.seo_title) ? (post.title || post.seo_title) : date(post.date, config.date_format) %> +

+
+ <% if (post.excerpt) { %> +

<%- strip_html(post.excerpt) %>

+ <% } else if (post.description) { %> +

<%- post.description %>

+ <% } else if (post.content && theme.article.auto_excerpt > 0) { %> +

<%- truncate(strip_html(post.content), {length: theme.article.auto_excerpt}) %>

+ <% } %> +
+
+ + + + <% if (showCat) { %> + <% if (post.layout == 'post' && post.categories && post.categories.length > 0) { %> + <% + var cats = []; + if (post.categories) { + post.categories.forEach((cat, i) => { + cats.push(cat.name); + }); + } + function layoutCats() { + if (cats.length > 0) { + var ret = ''; + ret += cats.shift() + ret += ''; + return ret; + } else { + return ''; + } + } + %> + <%- layoutCats() %> + <% } %> + <% } %> +
diff --git a/layout/_partial/post_list/wiki_card.ejs b/layout/_partial/post_list/wiki_card.ejs new file mode 100644 index 0000000..d3c72ad --- /dev/null +++ b/layout/_partial/post_list/wiki_card.ejs @@ -0,0 +1,41 @@ +<% if (post.logo) { %> + <% + var arr = post.logo.split(' '); + var height = ''; + var src = ''; + arr.forEach(function(item) { + var px = item.match(/[0-9]*px/i); + if (px && px.length > 0) { + px = px[0]; + height = px; + } else { + src = item; + } + }); + %> + +<% } %> +
+ +

<%- post.wiki || post.title %>

+ <% if (post.description) { %> +

<%- post.description %>

+ <% } else if (post.excerpt) { %> + <%- strip_html(post.excerpt) %> + <% } %> +
+ 了解详情 +
+
diff --git a/layout/_partial/scripts/global.ejs b/layout/_partial/scripts/global.ejs new file mode 100644 index 0000000..c2d0c0d --- /dev/null +++ b/layout/_partial/scripts/global.ejs @@ -0,0 +1,72 @@ + diff --git a/layout/_partial/scripts/index.ejs b/layout/_partial/scripts/index.ejs new file mode 100644 index 0000000..a7cdbf5 --- /dev/null +++ b/layout/_partial/scripts/index.ejs @@ -0,0 +1,30 @@ + +<%- partial('global') %> +<% if (theme.stellar.cdn_js) { %> + <%- js({src: theme.stellar.cdn_js, async: true}) %> +<% } else { %> + <%- js({src: 'js/main.js', async: true}) %> +<% } %> +<%- js({src: theme.plugins.jquery || 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js'}) %> + + + +<%- partial('lazyload') %> +<%- partial('preload') %> +<%- partial('swiper') %> + +<%- partial('scrollreveal') %> + + +<%- partial('../plugins/comments/script') %> + + +<% if (config.inject && config.inject.script && config.inject.script.length > 0) { %> + <% config.inject.script.forEach(function(js) { %> + <%- js %> + <% }) %> +<% } %> + + + +<%- partial('issues') %> diff --git a/layout/_partial/scripts/issues.ejs b/layout/_partial/scripts/issues.ejs new file mode 100644 index 0000000..f78d042 --- /dev/null +++ b/layout/_partial/scripts/issues.ejs @@ -0,0 +1,11 @@ + diff --git a/layout/_partial/scripts/lazyload.ejs b/layout/_partial/scripts/lazyload.ejs new file mode 100644 index 0000000..48bd52a --- /dev/null +++ b/layout/_partial/scripts/lazyload.ejs @@ -0,0 +1,25 @@ +<% if (theme.plugins.lazyload && theme.plugins.lazyload.enable) { %> + + + +<% } %> diff --git a/layout/_partial/scripts/preload.ejs b/layout/_partial/scripts/preload.ejs new file mode 100644 index 0000000..5db5783 --- /dev/null +++ b/layout/_partial/scripts/preload.ejs @@ -0,0 +1,16 @@ +<% if (theme.plugins.preload.enable && theme.plugins.preload.service) { %> + <% let preload = theme.plugins.preload; %> + <% if (preload.service == 'instant_page') { %> + + <% } else if (preload.service == 'flying_pages') { %> + + + <% } %> +<% } %> diff --git a/layout/_partial/scripts/scrollreveal.ejs b/layout/_partial/scripts/scrollreveal.ejs new file mode 100644 index 0000000..6760c34 --- /dev/null +++ b/layout/_partial/scripts/scrollreveal.ejs @@ -0,0 +1,12 @@ +<% if (theme.plugins.scrollreveal.enable && theme.plugins.scrollreveal.js) { %> + <%- js(theme.plugins.scrollreveal.js) %> + +<% } %> diff --git a/layout/_partial/scripts/swiper.ejs b/layout/_partial/scripts/swiper.ejs new file mode 100644 index 0000000..e9a2504 --- /dev/null +++ b/layout/_partial/scripts/swiper.ejs @@ -0,0 +1,29 @@ + diff --git a/layout/_partial/sidebar/header.ejs b/layout/_partial/sidebar/header.ejs new file mode 100644 index 0000000..2e2c927 --- /dev/null +++ b/layout/_partial/sidebar/header.ejs @@ -0,0 +1,17 @@ +
+ <%- partial('logo') %> + +
diff --git a/layout/_partial/sidebar/index.ejs b/layout/_partial/sidebar/index.ejs new file mode 100755 index 0000000..3b094fb --- /dev/null +++ b/layout/_partial/sidebar/index.ejs @@ -0,0 +1,38 @@ +<% +// 默认组件 +if (page.sidebar == undefined) { + if (page.layout == 'post' && page.content) { + page.sidebar = ['toc', 'recent']; + } else if (page.layout == 'wiki' && page.content) { + page.sidebar = ['toc', 'wiki_more']; + } else { + page.sidebar = ['welcome', 'recent']; + } +} +function layoutFooterDiv() { + if (theme.footer.social && theme.footer.social.length > 0) { + var el = ''; + return el; + } else { + return ''; + } +} +%> +
+ <%- partial('header') %> +
+ <% page.sidebar.forEach(function(widget){ %> + <% if (widget in theme.sidebar.widgets) { %> + <% let w = theme.sidebar.widgets[widget]; %> + <%- partial('widgets/' + w.layout, {item: w}) %> + <% } %> + <% }) %> +
+ <%- layoutFooterDiv() %> +
diff --git a/layout/_partial/sidebar/logo.ejs b/layout/_partial/sidebar/logo.ejs new file mode 100644 index 0000000..8c1040b --- /dev/null +++ b/layout/_partial/sidebar/logo.ejs @@ -0,0 +1,6 @@ + + <% if (theme.sidebar.logo.avatar != false) { %> +
+ <% } %> +
<%- theme.sidebar.logo.title || config.title %>
+
diff --git a/layout/_partial/sidebar/widgets/markdown.ejs b/layout/_partial/sidebar/widgets/markdown.ejs new file mode 100644 index 0000000..3f3736e --- /dev/null +++ b/layout/_partial/sidebar/widgets/markdown.ejs @@ -0,0 +1,10 @@ +
+
+ <%- item.title %> +
+
+ <% (item.content||[]).forEach(function(row){ %> + <%- markdown(row) %> + <% }) %> +
+
diff --git a/layout/_partial/sidebar/widgets/recent.ejs b/layout/_partial/sidebar/widgets/recent.ejs new file mode 100644 index 0000000..efe0f16 --- /dev/null +++ b/layout/_partial/sidebar/widgets/recent.ejs @@ -0,0 +1,30 @@ +
+
+ <%- __('meta.recent_update') %> + <% if (item.rss) { %> + + + + <% } %> +
+
+ <% + var arr = page.class == 'wiki' ? site.pages.filter(function(p){ + return p.layout == 'wiki' && p.title && p.title.length > 0; + }) : site.posts.filter(function(p){ + return p.title && p.title.length > 0; + }); + %> + <% arr.sort('updated', -1).limit(item.limit).each(function(post){ %> +
+ + <% if (post.wiki && (post.title.toUpperCase().includes(post.wiki.toUpperCase()) == false)) { %> + <%- post.wiki ? post.wiki + ': ' : '' %><%- post.title %> + <% } else { %> + <%- post.title %> + <% } %> + +
+ <% }) %> +
+
diff --git a/layout/_partial/sidebar/widgets/toc.ejs b/layout/_partial/sidebar/widgets/toc.ejs new file mode 100644 index 0000000..d7c0dfe --- /dev/null +++ b/layout/_partial/sidebar/widgets/toc.ejs @@ -0,0 +1,77 @@ +<% +var enable = false; +if (page.layout == 'post') { + if (page.content && toc(page.content).length > 0) { + enable = true; + } +} else if (page.layout == 'wiki' || page.sidebar.includes('toc') == true) { + enable = true; +} + +function layout_toc() { + if (toc(page.content).length > 0) { + return toc(page.content, { + list_number: item.list_number, + min_depth: item.min_depth, + max_depth: item.max_depth + }); + } +} + %> +<% if (enable == true) { %> +
+
+ + <% if (page.toc_title) { %> + <%- page.toc_title %> + <% } else if (page.layout == 'wiki') { %> + <%- page.wiki || item.wiki %> + <% } else { %> + <%- __('meta.toc') %> + <% } %> + + + + +
+
+ <% if (page.layout == 'wiki' && page.wiki) { %> + <% + var wikis = []; + wikis = site.pages.filter(function (p) { + if (p.layout == 'wiki' && p.wiki && p.wiki == page.wiki) { + if (p.order == undefined) { + p.order = 0; + } + return true; + } else { + return false; + } + }).sort('order'); + %> + <% if (wikis.length > 1) { %> + <% wikis.each(function(p) { %> + <% if (p.path == page.path) { %> +
+ <%- p.title || p.seo_title %> + <%- layout_toc() %> +
+ <% } else { %> + + <% } %> + <% }); %> + <% } else { %> +
+ <%- layout_toc() %> +
+ <% } %> + <% } else { %> +
+ <%- layout_toc() %> +
+ <% } %> +
+
+<% } %> diff --git a/layout/_partial/sidebar/widgets/wiki_more.ejs b/layout/_partial/sidebar/widgets/wiki_more.ejs new file mode 100644 index 0000000..671b770 --- /dev/null +++ b/layout/_partial/sidebar/widgets/wiki_more.ejs @@ -0,0 +1,28 @@ +<% if (page.layout == 'wiki') { %> + <% site.pages.filter(function (p) { %> + <% return p.layout == 'index' && p.title && p.wiki && p.wiki.includes(page.wiki) %> + <% }).limit(1).each(function(current_group) { %> + <% if (current_group.wiki.length > 1) { %> + + <% } %> + <% }); %> +<% } %> diff --git a/layout/archive.ejs b/layout/archive.ejs new file mode 100755 index 0000000..2e8d7d7 --- /dev/null +++ b/layout/archive.ejs @@ -0,0 +1,43 @@ +<% +if (page.class == undefined) { + page.class = 'post'; +} +%> +<% if (page.posts && (is_category() || is_tag())) { %> + <%- partial('index') %> +<% } else { %> + <% page.title = __('btn.archives'); %> + <%- partial('_partial/navbar/list_post') %> +
+ <% var years = []; %> + <% site.posts.sort('date', -1).each(function(post) { %> + <% post.year = date(post.date, 'YYYY'); %> + <% if (post.year && (years.includes(post.year) == false) && (post.title || post.date)) { %> + <% years.push(post.year); %> + <% } %> + <% }); %> +
<%- __('page.archives', years.length, site.posts.length) %>
+ <% years.forEach((year, i) => { %> +
+
<%= year %>
+ <% site.posts.sort('date', -1).filter(function (post) { %> + <% post.year = date(post.date, 'YYYY'); %> + <% return post.year == year; %> + <% }).each(function(post) { %> +
+ + + + <% if (post.title) { %> + <%- post.title %> + <% } else if (post.date) { %> + <%= date(post.date, config.date_format) %> + <% } %> + + +
+ <% }); %> +
+ <% }); %> +
+<% } %> diff --git a/layout/categories.ejs b/layout/categories.ejs new file mode 100755 index 0000000..fb74330 --- /dev/null +++ b/layout/categories.ejs @@ -0,0 +1,23 @@ +<% +if (page.class == undefined) { + page.class = 'post'; +} +%> +<% if (site.categories.length) { %> + <% page.title = __('btn.categories'); %> + <% page.layout = 'categories'; %> + <%- partial('_partial/navbar/list_post') %> +
+
<%- __('page.categories', site.categories.length) %>
+
+ <% site.categories.sort('path').each(function(category){ %> +
+ + <%- category.name %> + (<%- category.posts.length %>) + +
+ <% }) %> +
+
+<% } %> diff --git a/layout/index.ejs b/layout/index.ejs new file mode 100755 index 0000000..510578f --- /dev/null +++ b/layout/index.ejs @@ -0,0 +1,63 @@ +<% +if (page.class == undefined) { + if (page.layout == 'index' && page.title && page.wiki) { + page.class = 'wiki'; + } else { + page.class = 'post'; + } +} +%> +<% if (page.class == 'post') { %> + <%- partial('_partial/navbar/list_post') %> + <% if (page.posts) { %> +
+ <% page.posts.each(function(post){ %> + +
+ <%- partial('_partial/post_list/post_card', {post: post}) %> +
+
+ <% }) %> + <%- partial('_partial/post_list/paginator') %> +
+ <% } %> +<% } else if (page.class == 'wiki') { %> + <% function outputExcerpt(post) { %> + +
+ <%- partial('_partial/post_list/wiki_card', {post: post}) %> +
+
+ <% } %> + <%- partial('_partial/navbar/list_wiki') %> + <% if (page.title && page.wiki) { %> +
+ <% page.wiki.forEach((wiki, i) => { %> + <% site.pages.filter(function (p) { %> + <% return p.layout == 'wiki' && p.wiki == wiki && p.description; %> + <% }).limit(1).each(function(post) { %> + <%- outputExcerpt(post) %> + <% }); %> + <% }); %> +
+ <% } else { %> +
+ <% + var wikis = []; + wikis = site.pages.filter(function (p) { + if (p.layout == 'wiki' && p.wiki && p.description) { + if (p.order == undefined) { + p.order = 0; + } + return true; + } else { + return false; + } + }).sort('order'); + %> + <% wikis.forEach(function(post) { %> + <%- outputExcerpt(post) %> + <% }); %> +
+ <% } %> +<% } %> diff --git a/layout/layout.ejs b/layout/layout.ejs new file mode 100755 index 0000000..144456d --- /dev/null +++ b/layout/layout.ejs @@ -0,0 +1,21 @@ + + +<%- partial('_partial/head') %> + + <%- partial('_partial/article/wiki_cover') %> +
+ +
+ <%- partial('_partial/sidebar/header') %> + <%- body %> + + <%- partial('_partial/menubtn') %> +
+
+ <%- partial('_partial/scripts/index') %> + + diff --git a/layout/page.ejs b/layout/page.ejs new file mode 100755 index 0000000..d20aecd --- /dev/null +++ b/layout/page.ejs @@ -0,0 +1,12 @@ +<% if ((page.h1 && page.h1.length > 0) || (page.content && page.content.length > 0)) { %> + <%- partial('_partial/navbar/breadcrumb') %> +
+ <% if (page.h1 && page.h1.length > 0) { %> +

<%- page.h1 %>

+ <% } %> + <% if (page.content && page.content.length > 0) { %> + <%- page.content %> + <% } %> +
+<% } %> +<%- partial('_partial/plugins/comments/layout') %> diff --git a/layout/post.ejs b/layout/post.ejs new file mode 100755 index 0000000..6e0228e --- /dev/null +++ b/layout/post.ejs @@ -0,0 +1,15 @@ +<% +if (page.class == undefined) { + page.class = 'post'; +} +%> +<% let post = page; %> +<%- partial('_partial/navbar/breadcrumb') %> +
+

<%- post.h1 || post.title %>

+<%- post.content %> +
+<%- partial('_partial/article/references') %> +<%- partial('_partial/article/read_next') %> +<%- partial('_partial/article/related_posts') %> +<%- partial('_partial/plugins/comments/layout') %> diff --git a/layout/tags.ejs b/layout/tags.ejs new file mode 100755 index 0000000..1ad3c11 --- /dev/null +++ b/layout/tags.ejs @@ -0,0 +1,21 @@ +<% +if (page.class == undefined) { + page.class = 'post'; +} +%> +<% if (site.tags.length) { %> + <% page.title = __('btn.tags'); %> + <% page.layout = 'tags'; %> + <%- partial('_partial/navbar/list_post') %> +
+
<%- __('page.tags', site.tags.length) %>
+
+ <% site.tags.sort('length', -1).each(function(tag){ %> + + <%= tag.name %> + x<%- tag.length %> + + <% }) %> +
+
+<% } %> diff --git a/layout/wiki.ejs b/layout/wiki.ejs new file mode 100755 index 0000000..fe4b1fe --- /dev/null +++ b/layout/wiki.ejs @@ -0,0 +1,22 @@ +<% +if (page.class == undefined) { + page.class = 'wiki'; +} +if (page.layout == undefined) { + page.layout = 'index'; +} +if (page.title == undefined) { + page.title = 'Wiki'; +} +%> +<% if (page.layout == 'index') { %> + <%- partial('index') %> +<% } else { %> + <%- partial('_partial/navbar/breadcrumb') %> +
+

<%- page.h1 || page.title %>

+ <%- page.content %> +
+ <%- partial('_partial/article/read_next') %> + <%- partial('_partial/plugins/comments/layout') %> +<% } %> diff --git a/package.json b/package.json new file mode 100644 index 0000000..3e11497 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "hexo-theme-stellar", + "version": "1.0.0-rc.1", + "description": "Elegant and powerful theme for Hexo.", + "main": "package.json", + "scripts": { + "test": "echo test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/xaoxuu/hexo-theme-stellar.git" + }, + "keywords": [ + "hexo", + "theme", + "stellar" + ], + "author": "xaoxuu (https://github.com/xaoxuu/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/xaoxuu/hexo-theme-stellar/issues/" + }, + "homepage": "https://xaoxuu.com/wiki/stellar/", + "devDependencies": { + } +} diff --git a/publish.sh b/publish.sh new file mode 100644 index 0000000..9c233a9 --- /dev/null +++ b/publish.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# https://xaoxuu.com/wiki/stellar +# +# 只有 rc 阶段的测试版本和正式版本发布到 npm +# +# 1. 输入要发布的版本号 +# 2. 修改主题 _config.yml 中的 stellar.version +# 3. 修改主题 package.json 中的 version +# 4. 提交 commit + +# 版本号 例如 1.0.0-rc.1 +VERSION=$1 + +# 替换版本号 +function prepare() { + text="'"${VERSION}"'"" # This is theme's version." + sed -i "" "s/^ version:\([^\"]\{1,\}\)/ version: ${text}/g" '_config.yml' + sed -i "" "s/^ \"version\":\([^,]\{1,\}\)/ \"version\": \"${VERSION}\"/g" 'package.json' +} + +# 提交 +function commit() { + msg="release: ${VERSION}" + + printf "\n\n> \033[32m%s\033[0m" 'git add --all' + printf "\n" + git add --all + + printf "\n\n> \033[32m%s\033[0m" 'git commit -m' + printf " \033[35m%s\033[0m" ${msg} + printf "\n" + git commit -m "${msg}" + + printf "\n\n> \033[32m%s\033[0m" 'git push origin' + printf "\n" + git push origin + + # done + printf "\n\n> \033[32m%s\033[0m\n" 'Congratulations!' +} + + +while : +do + case $VERSION in + '') + read -p "请输入要发布的版本号: " VERSION + ;; + *) + break + ;; + esac +done + +prepare && commit diff --git a/scripts/events/index.js b/scripts/events/index.js new file mode 100644 index 0000000..7daf1b6 --- /dev/null +++ b/scripts/events/index.js @@ -0,0 +1,18 @@ +/* global hexo */ + +'use strict'; + +hexo.on('generateBefore', () => { + // Merge config. + require('./lib/config')(hexo); +}); + +hexo.on('ready', () => { + const { version } = require('../../package.json'); + hexo.log.info(` +=================================================== +Stellar ${version} +Docs: https://xaoxuu.com/wiki/stellar/ +Repo: https://github.com/xaoxuu/hexo-theme-stellar/ +===================================================`); +}); \ No newline at end of file diff --git a/scripts/events/lib/config.js b/scripts/events/lib/config.js new file mode 100644 index 0000000..ee52362 --- /dev/null +++ b/scripts/events/lib/config.js @@ -0,0 +1,41 @@ +/** + * 部分代码借鉴自 NexT: + * https://github.com/next-theme/hexo-theme-next/blob/master/scripts/events/lib/config.js + */ + +'use strict'; + +module.exports = hexo => { + + const { cache, language_switcher } = hexo.theme.config; + const warning = function(...args) { + hexo.log.warn(`Since ${args[0]} is turned on, the ${args[1]} is disabled to avoid potential hazards.`); + }; + + if (cache && cache.enable && language_switcher) { + warning('language_switcher', 'caching'); + cache.enable = false; + } + + if (cache && cache.enable && hexo.config.relative_link) { + warning('caching', '`relative_link` option in Hexo `_config.yml`'); + hexo.config.relative_link = false; + } + hexo.config.meta_generator = false; + + // merge data + const data = hexo.locals.get('data'); + if (data.widgets) { + for (let id of Object.keys(data.widgets)) { + hexo.theme.config.sidebar.widgets[id] = data.widgets[id]; + } + } + + + // default widgets + if (hexo.theme.config.sidebar.widgets.wiki_more == undefined) { + hexo.theme.config.sidebar.widgets.wiki_more = {layout: 'wiki_more'}; + } + + +}; diff --git a/scripts/filters/index.js b/scripts/filters/index.js new file mode 100644 index 0000000..2489935 --- /dev/null +++ b/scripts/filters/index.js @@ -0,0 +1,5 @@ +'use strict'; + + +hexo.extend.filter.register('after_post_render', require('./lib/lazyload').processPost); +hexo.extend.filter.register('after_render:html', require('./lib/lazyload').processSite); diff --git a/scripts/filters/lib/lazyload.js b/scripts/filters/lib/lazyload.js new file mode 100644 index 0000000..6b0926c --- /dev/null +++ b/scripts/filters/lib/lazyload.js @@ -0,0 +1,67 @@ +'use strict'; + +const fs = require('hexo-fs'); + +function lazyProcess(htmlContent, target) { + const cfg = this.theme.config.plugins.lazyload; + if (cfg == undefined || cfg.enable != true) { + return htmlContent; + } + if (cfg.onlypost == true) { + if (target != 'post') { + return htmlContent; + } + } + const loadingImg = cfg.loadingImg; + return htmlContent.replace(//gi, function(str, p1, p2) { + // might be duplicate + if (/data-srcset/gi.test(str)) { + return str; + } + if (/src="data:image(.*?)/gi.test(str)) { + return str; + } + if (/no-lazy/gi.test(str)) { + return str; + } + let cls = ''; + if (str.indexOf('class=') > -1) { + cls = str.substring(str.indexOf('class=')); + if (cls.length > 7) { + const c = cls.substring(6, 7); + cls = cls.split(c); + if (cls.length > 1) { + cls = cls[0] + '"' + cls[1] + '"'; + } + } + } + let result = str; + let newCls = ''; + if (cls.length > 0 && result.includes('class=')) { + newCls = cls.replace(/(class=|[\"]*)/g, '') + ' '; + } + const oldCls = newCls.trim(); + if (loadingImg) { + newCls += 'lazyload placeholder'; + } else { + newCls += 'lazyload'; + } + if (cls.length > 0) { + result = result.replace('"' + oldCls + '"', '"' + newCls + '"'); + } + if (loadingImg) { + return result.replace(p2, p2 + '" class="lazyload placeholder" ' + 'data-srcset="' + p2 + '" srcset="' + loadingImg); + } + return result.replace(p2, p2 + '" class="lazyload" ' + 'data-srcset="' + p2 + '" srcset="' + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAAaADAAQAAAABAAAAAQAAAADa6r/EAAAAC0lEQVQIHWNgAAIAAAUAAY27m/MAAAAASUVORK5CYII='); + + }); +} + +module.exports.processPost = function(data) { + data.content = lazyProcess.call(this, data.content, 'post'); + return data; +}; + +module.exports.processSite = function(htmlContent) { + return lazyProcess.call(this, htmlContent, 'site'); +}; diff --git a/scripts/generators/404.js b/scripts/generators/404.js new file mode 100644 index 0000000..942532a --- /dev/null +++ b/scripts/generators/404.js @@ -0,0 +1,10 @@ +/** + * 404 v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + */ + +hexo.extend.generator.register('404', function (locals) { + return { + path: '/404.html', + layout: ['404'] + } +}); \ No newline at end of file diff --git a/scripts/generators/categories.js b/scripts/generators/categories.js new file mode 100644 index 0000000..410a3fa --- /dev/null +++ b/scripts/generators/categories.js @@ -0,0 +1,11 @@ +/** + * categories v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + */ + +hexo.extend.generator.register('categories', function (locals) { + return { + path: hexo.config.category_dir + '/index.html', + data: locals.posts, + layout: ['categories'] + } +}); \ No newline at end of file diff --git a/scripts/generators/tags.js b/scripts/generators/tags.js new file mode 100644 index 0000000..09eb19c --- /dev/null +++ b/scripts/generators/tags.js @@ -0,0 +1,11 @@ +/** + * tags v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + */ + + hexo.extend.generator.register('tags', function (locals) { + return { + path: hexo.config.tag_dir + '/index.html', + data: locals.posts, + layout: ['tags'] + } +}); \ No newline at end of file diff --git a/scripts/generators/wiki.js b/scripts/generators/wiki.js new file mode 100644 index 0000000..27aef64 --- /dev/null +++ b/scripts/generators/wiki.js @@ -0,0 +1,11 @@ +/** + * wiki v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + */ + +hexo.extend.generator.register('wiki', function (locals) { + return { + path: (hexo.config.wiki_dir || 'wiki') + '/index.html', + data: locals.posts, + layout: ['wiki'] + } +}); \ No newline at end of file diff --git a/scripts/helpers/related_posts.js b/scripts/helpers/related_posts.js new file mode 100644 index 0000000..ea6cfe8 --- /dev/null +++ b/scripts/helpers/related_posts.js @@ -0,0 +1,54 @@ +/** + * https://github.com/tea3/hexo-related-popular-posts/wiki/More-Settings#customize-html + */ + +'use strict'; +var util = require('hexo-util'); + +// Examples of helper +hexo.extend.helper.register('popular_posts_wrapper', function(args){ + if (!args || !args.json || args.json.length == 0) return ""; + const cfg = hexo.theme.config.article.related_posts; + if (cfg.enable != true) return; + var returnHTML = ""; + var div = ` + '; + return div; +}); diff --git a/scripts/tags/about.js b/scripts/tags/about.js new file mode 100644 index 0000000..bb63cd9 --- /dev/null +++ b/scripts/tags/about.js @@ -0,0 +1,46 @@ +/** + * about.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% about [avatar:xxx] [height:80px] %} + * title / body + * {% endabout %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('about', function(args, content) { + args = ArgsMap(args, ['avatar', 'height']); + var rows = hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n'); + var el = ''; + // wrapper + el += '
'; + el += '
'; + // avatar + el += '
' + el += ' 0) { + el += ' height="' + args.height + '"/>'; + } else { + el += '/>'; + } + el += '
'; + // title + if (rows.length > 0) { + // el += '
'; + el += rows.shift(); + // el += '
'; + } + + el += '
'; + + // content + el += '
'; + el += rows.join(''); + el += '
'; + + el += '
'; + return el; +}, {ends: true}); diff --git a/scripts/tags/checkbox.js b/scripts/tags/checkbox.js new file mode 100644 index 0000000..662af11 --- /dev/null +++ b/scripts/tags/checkbox.js @@ -0,0 +1,40 @@ +/** + * checkbox.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * radio.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% checkbox [checked:false] [color:cyan] [symbol:plus/minus/times] text %} + * {% radio [checked:false] [color:cyan] text %} + */ + +'use strict'; + +const { ArgsMap, ArgsJoinTags } = require('./utils'); + +function layoutDiv(args, type) { + args = ArgsMap(args, ['color', 'checked', 'symbol'], ['text']); + var el = ''; + // div + el += '
'; + // div + el += '
'; + return el; +} + +hexo.extend.tag.register('checkbox', function(args) { + return layoutDiv(args, 'checkbox'); +}); + +hexo.extend.tag.register('radio', function(args) { + return layoutDiv(args, 'radio'); +}); diff --git a/scripts/tags/folding.js b/scripts/tags/folding.js new file mode 100644 index 0000000..59df2a5 --- /dev/null +++ b/scripts/tags/folding.js @@ -0,0 +1,32 @@ +/** + * folding.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% folding [color:yellow] [codeblock:false] [open:false] title %} + * body + * {% endtable %} + */ + +'use strict'; + +const { ArgsMap, ArgsJoinTags } = require('./utils'); + +hexo.extend.tag.register('folding', function(args, content) { + args = ArgsMap(args, ['color', 'codeblock', 'open'], ['title']); + var el = ''; + // header + el += '
'; + // content + el += '
'; + el += hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join(''); + el += '
'; + + return el; +}, {ends: true}); diff --git a/scripts/tags/frame.js b/scripts/tags/frame.js new file mode 100644 index 0000000..b230bed --- /dev/null +++ b/scripts/tags/frame.js @@ -0,0 +1,68 @@ +/** + * frame.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% frame iphone11 [img:src] [video:url] [focus:top/bottom] [alt] %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('frame', function(args) { + args = ArgsMap(args, ['focus', 'img', 'video'], ['device', 'alt']); + const img = args.img || ''; + const video = args.video || ''; + const device = args.device || ''; + const focus = args.focus || ''; + const alt = args.alt || ''; + if ((img.length == 0 && video.length == 0) || device.length == 0) { + return; + } + var el = ''; + function imgTag(url, alt) { + let i = ''; + i += ' 0) { + i += ' alt="' + alt + '"'; + } + i += '/>'; + return i; + } + if (video.length > 0) { + el += '
'; + el += '
0) { + el += 'focus="' + focus + '">'; + } else { + el += '>'; + } + el += ' 0) { + el += ' poster="' + img + '"'; + } + el += ' playsinline="" muted="" loop="" autoplay="" preload="metadata">'; + el += ''; + el += ''; + + el += '
'; + el += '
'; + el += '
'; + } else if (img.length > 0) { + el += '
'; + el += '
0) { + el += 'focus="' + focus + '">'; + } else { + el += '>'; + } + el += imgTag(img, alt); + el += '
'; + el += '
'; + if (alt.length > 0) { + el += '' + alt + ''; + } + el += '
'; + } + return el; +}); diff --git a/scripts/tags/friends.js b/scripts/tags/friends.js new file mode 100644 index 0000000..923d12f --- /dev/null +++ b/scripts/tags/friends.js @@ -0,0 +1,66 @@ +/** + * friends.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% friends [style:rect] [group:name] %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('friends', function(args) { + args = ArgsMap(args, ['style', 'group']); + var friends = hexo.locals.get('data').friends; + if (friends == undefined) { + return; + } + var el = '
'; + function groupHeader(group) { + var header = '
'; + header += '

' + group.title + '

'; + header += '

' + group.description + '

'; + header += '
'; + return header; + } + function cell(friend) { + if (friend.url && friend.title) { + var cell = '' + return cell; + } else { + return ''; + } + } + for (let groupId of Object.keys(friends)) { + function f() { + if (groupId in friends) { + let group = friends[groupId]; + el += groupHeader(group); + el += '
'; + group.items.forEach((friend, i) => { + el += cell(friend); + }); + el += '
'; + } + } + if (args.group && args.group.length > 0) { + if (args.group == groupId) { + f(); + } + } else { + f(); + } + } + el += '
'; + return el; +}); diff --git a/scripts/tags/ghcard.js b/scripts/tags/ghcard.js new file mode 100644 index 0000000..7184b19 --- /dev/null +++ b/scripts/tags/ghcard.js @@ -0,0 +1,41 @@ +/** + * friends.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% ghcard user/repo [theme:xxx] %} or {% ghcard user %} + * + * example: + * {% ghcard xaoxuu %} + * {% ghcard xaoxuu/hexo-theme-stellar %} + * + * API: https://github.com/anuraghazra/github-readme-stats + */ + +'use strict'; + +const { ArgsMap, ArgsJoinURLParams } = require('./utils'); + +hexo.extend.tag.register('ghcard', function(args) { + var params = ['show_owner', 'theme', 'title_color', 'text_color', 'icon_color', 'bg_color', 'hide_border', 'cache_seconds', 'locale']; + args = ArgsMap(args, params, ['repo']); + const path = args.repo; + var el = ''; + el += '
'; + el += ''; + let url = ''; + if (path.includes('/')) { + // is repo + const ps = path.split('/'); + url += 'https://github-readme-stats.vercel.app/api/pin/?username=' + ps[0] + '&repo=' + ps[1]; + } else { + // is user + url += 'https://github-readme-stats.vercel.app/api/?username=' + path; + } + url += '&' + ArgsJoinURLParams(args, params); + if (!url.includes('&show_owner=')) { + url += '&show_owner=true'; + } + el += ''; + el += '
'; + return el; +}); diff --git a/scripts/tags/image.js b/scripts/tags/image.js new file mode 100644 index 0000000..4f21d1b --- /dev/null +++ b/scripts/tags/image.js @@ -0,0 +1,66 @@ +/** + * image.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% image src [alt] [width:400px] [bg:#eee] [download:true/false/url] %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('image', function(args) { + args = ArgsMap(args, ['width', 'height', 'bg', 'download', 'padding'], ['src', 'alt']); + var style = ''; + if (args.width) { + style += 'width:' + args.width + ';'; + } + if (args.height) { + style += 'height:' + args.height + ';'; + } + if (args.padding) { + style += 'padding:' + args.padding + ';'; + } + function img(src, alt, style) { + let img = ''; + img += ' 0) { + img += ' style="' + style + '"'; + } + img += '/>'; + return img; + } + + var el = ''; + // wrap + el += '
'; + // bg + el += '
0) { + el += ' style="background:' + args.bg + '"'; + } + el += '>'; + el += img(args.src, args.alt, style); + el += '
'; + + if (args.alt && args.alt.length > 0) { + el += '
'; + if (args.download && args.download.length > 0) { + el += '' + args.alt + ''; + let href = args.download; + if (args.download == 'true') { + href = args.src; + } + el += ''; + } else { + el += '' + args.alt + ''; + } + el += '
'; + } + + el += '
'; + return el; +}); diff --git a/scripts/tags/issues.js b/scripts/tags/issues.js new file mode 100644 index 0000000..59bacbb --- /dev/null +++ b/scripts/tags/issues.js @@ -0,0 +1,32 @@ +/** + * issues.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% issues [sites/timeline/friends] api:xxx [group:key=value1,value2,value3] %} + * + * example: + * {% issues sites api:https://api.github.com/repos/volantis-x/examples/issues?sort=updated&state=open&page=1&per_page=100 group:version=版本:^4.0,版本:^3.0,版本:^2.0 %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('issues', function(args) { + args = ArgsMap(args, ['api', 'group'], ['type']); + // 所有支持的参数 + let type = args.type || ''; + let api = args.api || ''; + let group = args.group || ''; + if (type.length == 0 || api.length == 0) { + return; + } + // 布局 + var el = '
0) { + el += 'group="' + group + '"'; + } + el += '>
'; + return el; +}); diff --git a/scripts/tags/link.js b/scripts/tags/link.js new file mode 100644 index 0000000..d9f2c6d --- /dev/null +++ b/scripts/tags/link.js @@ -0,0 +1,32 @@ +/** + * link.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% link url title [description] [img:src] %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +hexo.extend.tag.register('link', function(args) { + args = ArgsMap(args, ['src'], ['url', 'title', 'description']); + var el = ''; + el += ''; + + return el; +}); diff --git a/scripts/tags/navbar.js b/scripts/tags/navbar.js new file mode 100644 index 0000000..f97d998 --- /dev/null +++ b/scripts/tags/navbar.js @@ -0,0 +1,38 @@ +/** + * navbar.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% navbar [markdown link] ... %} + * + * example: + * {% navbar [Home](/) [About](/about/) [Comments](#comments) %} + */ + +'use strict'; + +hexo.extend.tag.register('navbar', function(args) { + if (args.length == 0) { + return; + } + var el = ''; + return el; +}); diff --git a/scripts/tags/note.js b/scripts/tags/note.js new file mode 100644 index 0000000..a7258b0 --- /dev/null +++ b/scripts/tags/note.js @@ -0,0 +1,54 @@ +/** + * note.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * note: + * {% note [color:color] [title] content %} + * + * noteblock: + * {% noteblock [color:color] title %} + * markdown content + * {% endnoteblock %} + */ + +'use strict'; + +const { ArgsMap } = require('./utils'); + +function outputNoteBlock(color, title, content) { + var el = ''; + const defaultColor = hexo.theme.config.tag_plugins.note.default_color; + if (!color && defaultColor) { + color = defaultColor; + } + // header + el += '
0) { + el += ' color="' + color + '"'; + } + el += '>'; + // title + if (title && title.length > 0) { + el += '
' + title + '
'; + } + // content + el += '
'; + el += hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join(''); + el += '
'; + + return el; +} + +hexo.extend.tag.register('note', function(args) { + args = ArgsMap(args, ['color'], ['title', 'content']); + if (args.content) { + return outputNoteBlock(args.color, args.title, args.content); + } else { + return outputNoteBlock(args.color, '', args.title); + } +}); + +hexo.extend.tag.register('noteblock', function(args, content) { + args = ArgsMap(args, ['color'], ['title']); + return outputNoteBlock(args.color, args.title, content); +}, {ends: true}); diff --git a/scripts/tags/swiper.js b/scripts/tags/swiper.js new file mode 100644 index 0000000..97b98f5 --- /dev/null +++ b/scripts/tags/swiper.js @@ -0,0 +1,39 @@ +/** + * swiper.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来) + * + * {% swiper %} + * ![img](src) + * {% endswiper %} + */ + +'use strict'; + +const { ArgsMap, ArgsJoinTags } = require('./utils'); + +hexo.extend.tag.register('swiper', function(args, content) { + args = ArgsMap(args, ['width']); + var el = ''; + function slide() { + let imgs = hexo.render.renderSync({text: content, engine: 'markdown'}); + imgs = imgs.match(//gi); + if (imgs && imgs.length > 0) { + imgs.forEach((img, i) => { + el += '
' + img + '
'; + }); + } + } + el += '
0) { + el += ' ' + ArgsJoinTags(args, 'width').join(' '); + } + el += '>'; + el += '
'; + slide(); + el += '
'; + el += '
'; + el += '
'; + el += '
'; + el += '
'; + return el; +}, {ends: true}); diff --git a/scripts/tags/timeline.js b/scripts/tags/timeline.js new file mode 100644 index 0000000..c20abaf --- /dev/null +++ b/scripts/tags/timeline.js @@ -0,0 +1,40 @@ +/** + * timeline.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + * + * {% timeline %} + * + * {% timenode header1 %} + * what happened 1 + * {% endtimenode %} + * + * {% timenode header2 %} + * what happened 2 + * {% endtimenode %} + * + * {% endtimeline %} + */ + +'use strict'; + +function postTimeline(args, content) { + return `
+ +${content} + +
`; +} + +function postTimenode(args, content) { + args = args.join(' ').split(', '); + var header = args[0]; + return `
${header} + + + + +
${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')}
`; +} + +hexo.extend.tag.register('timeline', postTimeline, {ends: true}); + +hexo.extend.tag.register('timenode', postTimenode, {ends: true}); diff --git a/scripts/tags/utils.js b/scripts/tags/utils.js new file mode 100644 index 0000000..91015db --- /dev/null +++ b/scripts/tags/utils.js @@ -0,0 +1,72 @@ +/** + * folding.js v1 | https://github.com/xaoxuu/hexo-theme-stellar/ + */ + +'use strict'; + + +module.exports = { + ArgsMap(args, keys, others) { + if (Array.isArray(args) == false) { + return args; + } + var map = {others: Array()}; + args.forEach((arg, i) => { + let kv = arg.trim(); + if (kv.includes('://') && kv.split(':').length == 2) { + // 纯 url + map.others.push(kv); + } else { + kv = kv.split(':'); + if (kv.length > 1) { + if (keys.includes(kv[0]) == true) { + map[kv.shift()] = kv.join(':'); + } else { + map.others.push(kv.join(':')); + } + } else if (kv.length == 1) { + map.others.push(kv[0]); + } + } + }); + // 解析不带 key 的参数 + if (others && others.length > 0 && map.others.length > 0) { + if (Array.isArray(others) == false) { + others = [others]; + } + others.forEach((arg, i) => { + map[arg] = map.others.shift(); + }); + // 最后一段合并到最后一个参数中 + if (map.others.length > 0) { + map[others[others.length-1]] += ' ' + map.others.join(' '); + map.others = []; + } + } + return map; + }, + ArgsJoinTags(args, keys) { + if (Array.isArray(keys) == false) { + keys = [keys]; + } + var ret = []; + keys.forEach((key, i) => { + if (args[key] && args[key].length > 0) { + ret.push(key + '="' + args[key] + '"'); + } + }); + return ret; + }, + ArgsJoinURLParams(args, keys) { + if (Array.isArray(keys) == false) { + keys = [keys]; + } + var ret = []; + keys.forEach((key, i) => { + if (args[key] && args[key].length > 0) { + ret.push(key + '=' + args[key]); + } + }); + return ret.join('&'); + } +}; diff --git a/source/css/_custom.styl b/source/css/_custom.styl new file mode 100644 index 0000000..d62d659 --- /dev/null +++ b/source/css/_custom.styl @@ -0,0 +1,74 @@ +@require('_defines/base') +@require('_defines/const') + +// 通用主题色 +$color-theme = #1BCDFC +$color-link = #2196f3 +$color-button = #1BCDFC +$color-hover = #ff5722 +$color-inner = #fff +$color-inlinecode = #D56D28 +$color-cat = #FF7844 +$color-cat-hover = darken($color-cat, 20) + +// 浅色页面 +$c-site-bg-light = #f8f8f8 +$c-block-light = #f2f2f2 +$c-title-light = #111 +$c-text-light = #333 +$c-card-light = white + +// 深色页面 +$c-site-bg-dark = black +$c-block-dark = #111 +$c-title-dark = #fff +$c-text-dark = #fff +$c-card-dark = #333 + + + +// @font-face +// font-family: 'Dosis' +// src: url('https://cdn.jsdelivr.net/gh/volantis-x/cdn-fonts@20.5.30/Dosis/Dosis-Medium.ttf') +// font-weight: normal +// font-style: normal + +$ff-body = Dosis, -apple-system, "Helvetica Neue", Helvetica, Arial, "WenQuanYi Micro Hei", "Microsoft Yahei", Menlo, Monaco, monospace, courier, sans-serif +$ff-code = Menlo, Monaco, monospace, courier, sans-serif + +$ff-logo = $ff-body + +// font size +$fs-root = 16px +$fs-h1 = 2rem // 32px +$fs-h2 = 1.625rem // 26px +$fs-h3 = 1.375rem // 22px +$fs-h4 = 1.125rem // 18px +$fs-h5 = 1rem // 16px +$fs-h6 = 1rem // 16px +$fs15 = .9375rem // 15px +$fs14 = .875rem // 14px +$fs13 = .8125rem // 13px +$fs-code = .8125rem // 13px +$fs12 = .75rem // 13px +$fs-footnote = .75rem // the smallest (12px) + + +// site layout +$sidebar = 280px + +// max body width +$layout-max-body-width = 720px + +// gap +$gap = 16px // 必须是 px + +// border radius +$border-card = 12px +$border-block = 4px + + +// shadow +$boxshadow-card = 0 1px 2px 0px rgba(0, 0, 0, 0.1) +$boxshadow-float = 0 4px 8px 0px rgba(0, 0, 0, 0.1) +$boxshadow-card-float = 0 2px 4px 0px rgba(0, 0, 0, 0.1), 0 4px 8px 0px rgba(0, 0, 0, 0.1), 0 8px 16px 0px rgba(0, 0, 0, 0.1) diff --git a/source/css/_defines/base.styl b/source/css/_defines/base.styl new file mode 100644 index 0000000..2833bdd --- /dev/null +++ b/source/css/_defines/base.styl @@ -0,0 +1,43 @@ + +// 可替代 transition 使用 +transition($op = all, $time = 0.28s, $ease = ease-out) + transition: $op $time $ease + -moz-transition: $op $time $ease + -webkit-transition: $op $time $ease + -o-transition: $op $time $ease + +// 为1个属性设置动画 +trans1($op, $time = 0.2s) + transition: $op $time ease-out + -moz-transition: $op $time ease-out + -webkit-transition: $op $time ease-out + -o-transition: $op $time ease-out + +// 为2个属性设置动画 +trans2($op1, $op2) + transition: $op1 0.2s ease-out, $op2 0.2s ease-out + -moz-transition: $op1 0.2s ease-out, $op2 0.2s ease-out + -webkit-transition: $op1 0.2s ease-out, $op2 0.2s ease-out + -o-transition: $op1 0.2s ease-out, $op2 0.2s ease-out + + +txt-ellipsis() + white-space: nowrap + overflow: hidden + text-overflow: ellipsis + +placeholder(rules) + &::-webkit-input-placeholder + rules() + &:-moz-placeholder + rules() + &::-moz-placeholder + rules() + &:-ms-input-placeholder + rules() + +disable-select() + -moz-user-select: none + -ms-user-select: none + -webkit-user-select: none + user-select: none diff --git a/source/css/_defines/const.styl b/source/css/_defines/const.styl new file mode 100644 index 0000000..854afb8 --- /dev/null +++ b/source/css/_defines/const.styl @@ -0,0 +1,50 @@ + +// device defines +$device-mobile-s = 320px +$device-mobile-m = 375px +$device-mobile-l = 425px +$device-mobile = 500px +$device-tablet = 768px +$device-laptop = 1024px +$device-desktop = 1440px +$device-2k = 2048px +$device-4k = 2560px + +// -------- 这些是方便开发预定义的颜色,不需要动态改变 -------- +$color-md-red = #f44336 +$color-md-pink = #E91E63 +$color-md-purple = #9c27b0 +$color-md-deep-purple = #673ab7 +$color-md-indigo = #3f51b5 +$color-md-light-blue = #4BA7EE +$color-md-blue = #2196f3 +$color-md-deep-blue = #3367d6 +$color-md-teal = #009688 +$color-md-green = #4caf50 +$color-md-light-green = #8bc34a +$color-md-orange = #ff9800 +$color-md-deep-orange = #ff5722 +$color-md-brown = #795548 +$color-md-blue-grey = #607d8b +$color-md-grey = #9e9e9e +$color-md-light-grey =#e0e0e0 +$color-md-yellow = #FCEC60 +$color-md-amber = #F6C344 + +$color-mac-cyan = #1BCDFC +$color-mac-green = #3DC550 +$color-mac-yellow = #FFBD2B +$color-mac-red = #FE5F58 + +$color-google-blue = #4688F1 +$color-google-green = #3AA757 +$color-google-yellow = #FABB2D +$color-google-red = #E8453C + +$c-red = #F44336 +$c-orange = #FA6400 +$c-yellow = #FFBD2B +$c-green = #3DC550 +$c-cyan = #1BCDFC +$c-blue = #2196f3 +$c-purple = #9c27b0 diff --git a/source/css/_defines/func.styl b/source/css/_defines/func.styl new file mode 100644 index 0000000..864387d --- /dev/null +++ b/source/css/_defines/func.styl @@ -0,0 +1,51 @@ + + +scrollbar($w = 4px, $b = 2px, $c = var(--text-meta), $h = var(--text-p3)) + &::-webkit-scrollbar + height: $w + width: $w + &::-webkit-scrollbar-track-piece + background: transparent + &::-webkit-scrollbar-thumb + background: $c + cursor: pointer + border-radius: $b + &:hover + background: $h + + +scrollbar-codeblock() + &::-webkit-scrollbar + height: 4px + width: 4px + &::-webkit-scrollbar-track-piece + background: transparent + &::-webkit-scrollbar-thumb + background: transparent + cursor: pointer + border-radius: $border-block + &:hover + &::-webkit-scrollbar-thumb + background: var(--text-meta) + &:hover + background: var(--text-p3) + + +hover-block($v, $h, $br = 4px) + border-radius: $br + padding: $v $h + trans2 color background + &:hover + background: var(--hover-block) + + +inside-box($fs = $fs15) + p,ol,ul + margin-top: 0.5rem + margin-bottom: 0.5rem + &:first-child + margin-top: 0 + &:last-child + margin-bottom: 0 + p,li + font-size: $fs diff --git a/source/css/_defines/theme.styl b/source/css/_defines/theme.styl new file mode 100644 index 0000000..7fceb41 --- /dev/null +++ b/source/css/_defines/theme.styl @@ -0,0 +1,27 @@ +:root + --site-bg: $c-site-bg-light + --block: $c-block-light + --block-border: mix($c-block-light, $c-text-light, 95) + --hover-block: mix($c-block-light, $c-text-light, 98) + --text-p0: $c-title-light + --text-p1: $c-text-light + --text-p2: mix($c-text-light, $c-site-bg-light, 80) + --text-p3: mix($c-text-light, $c-site-bg-light, 60) + --text-meta: mix($c-text-light, $c-site-bg-light, 20) + --card: $c-card-light + --theme-highlight: darken($color-theme, 5) + --theme-bg: mix($color-theme, $c-card-light, 10) + +body[theme='dark'] + --site-bg: $c-site-bg-dark + --block: $c-block-dark + --block-border: mix($c-block-dark, $c-text-dark, 90) + --hover-block: mix($c-block-dark, $c-text-dark, 95) + --text-p0: $c-title-dark + --text-p1: $c-text-dark + --text-p2: mix($c-text-dark, $c-site-bg-dark, 70) + --text-p3: mix($c-text-dark, $c-site-bg-dark, 45) + --text-meta: mix($c-text-dark, $c-site-bg-dark, 30) + --card: $c-card-dark + --theme-highlight: $color-theme + --theme-bg: mix($color-theme, $c-card-dark, 10) diff --git a/source/css/_layout/base.styl b/source/css/_layout/base.styl new file mode 100644 index 0000000..1351a7f --- /dev/null +++ b/source/css/_layout/base.styl @@ -0,0 +1,129 @@ +* + outline: none +html + font-family: $ff-body + font-size: $fs-root + +body + background: var(--site-bg) + margin: 0 + -webkit-font-smoothing: antialiased + -moz-osx-font-smoothing: grayscale + text-rendering: optimizelegibility + -webkit-tap-highlight-color: rgba(0, 0, 0, 0) + + +h1 + font-size: $fs-h1 + font-weight: 600 + +pre + font-family: $ff-code + font-size: $fs-code + tab-size: 4 + -moz-tab-size: 4 + -o-tab-size: 4 + -webkit-tab-size: 4 + +a + text-decoration: none + color: $color-link + &:hover + color: $color-hover + +a.button + font-weight: 500 + line-height: 1 + padding: 0.75rem 2rem + border-radius: 3px + trans1: background + font-size: $fs15 + &.cyan + background: $color-mac-cyan + color: white + &:hover + background: $color-hover + + +.cap + font-weight: 600 + font-size: $fs12 + color: var(--text-p3) + &.breadcrumb + color: $color-cat + &.blue + color: darken($color-md-blue, 6) + &.cyan + color: darken($color-mac-cyan, 6) + &.green + color: darken($color-mac-green, 4) + + +span.dot,span.sep + font-size: 0.9em + margin: 0 .25em +span.dot:before + content: '·' +span.sep:before + content: '/' + +hr + color: var(--text-meta) + opacity: .1 + +button + padding: 1em + border: none + font-weight: 600 + outline: none + disable-select() + &:hover + color: $color-inner + background: $color-theme + +img + max-width: 100% + + +li + font-size: $fs15 + +svg.icon + width: 1em + height: 1em + vertical-align: middle + fill: currentColor + overflow: hidden + +ul,ol + padding-left: 1.5rem + +ul ul, ul ol + padding-left: 0 +ol ul, ol ol + padding-left: 0 + +.dis-select + disable-select() + + +// table +table:not([class]) + border-collapse: collapse + overflow: auto + display: inline-block + max-width: 100% + vertical-align: text-top + th + background: var(--hover-block) + td,th + padding: 8px 16px + border: 2px solid var(--hover-block) + line-height: 1.5 + font-size: 90% + tr + word-break: keep-all + background: var(--block) + trans() + &:hover + background: var(--hover-block) diff --git a/source/css/_layout/footer.styl b/source/css/_layout/footer.styl new file mode 100644 index 0000000..7a51cf8 --- /dev/null +++ b/source/css/_layout/footer.styl @@ -0,0 +1,12 @@ +.page-footer + margin: $gap + font-size: $fs12 + color: var(--text-p3) + p + margin: 4px 0 + line-height: 1.2 + a + color: var(--text-p3) + text-decoration: underline + &:hover + color: $color-hover diff --git a/source/css/_layout/highlight.styl b/source/css/_layout/highlight.styl new file mode 100644 index 0000000..5d9bc7e --- /dev/null +++ b/source/css/_layout/highlight.styl @@ -0,0 +1,238 @@ +article.md .highlight + margin: 1rem 0 + border-radius: $border-block + -webkit-font-smoothing: auto + -moz-osx-font-smoothing: auto + overflow: hidden + // width: "calc(100% - 2px)" + width: 100% + background: var(--block) + border: 1px solid var(--block-border) + line-height: 1.5 + font-family: $ff-code + +article.md .highlight + position: relative + overflow: auto + display: block + figcaption + color: var(--text-p2) + font-size: $fs-code + padding: 4px 0.5rem + position: sticky + left: 0 + background: var(--hover-block) + border-top-left-radius: "calc(%s - 1px)" % $border-block + border-top-right-radius: "calc(%s - 1px)" % $border-block + border-bottom: 1px solid var(--block-border) + span + margin-right: 4px + >table + overflow: auto + display: block + td,th + padding: 0 + border: none + line-height: 1.5 + margin: 0 + background: transparent + border: none + scrollbar-codeblock() + tr + background: transparent + &:hover + background: transparent + + + .gutter + pointer-events: none + disable-select() + text-align: right + padding: 0 1em + border-width: 0 + margin-left: 0 + position: sticky + left: 0 + z-index: 1 + background: var(--block) + pre .line + color: var(--text-p2) + .code + pre + display: block + padding: .5em 1rem + .gutter+.code pre + padding-left: 0.25em + + +table:not([class]) + border-collapse: collapse + +article.md .highlight + .code + vertical-align: top + &:before + content: "" + position: absolute + top: 0 + right: 0 + padding: 4px 0.5rem + opacity: .25 + font-weight: 700 + + &.yaml .code:before + content: "YAML" + &.json .code:before + content: "JSON" + + &.diff .code:before + content: "diff" + + &.html .code:before + content: "HTML" + &.js .code:before,&.javascript .code:before + content: "JS" + &.css .code:before + content: "CSS" + &.less .code:before + content: "Less" + &.stylus .code:before + content: "Stylus" + + &.bash .code:before + content: "bash" + &.shell .code:before + content: "shell" + &.sh .code:before + content: "sh" + &.ini .code:before + content: "ini" + + &.c .code:before + content: "C" + &.cpp .code:before + content: "C++" + &.objc .code:before,&.objectivec .code:before + content: "Objective-C" + &.swift .code:before + content: "Swift" + + &.java .code:before + content: "Java" + &.python .code:before + content: "Python" + &.php .code:before + content: "PHP" + &.rust .code:before + content: "Rust" + &.sql .code:before + content: "SQL" + &.ruby .code:before + content: "Ruby" + &.makefile .code:before + content: "Makefile" + &.go .code:before + content: "Go" + &.typescript .code:before + content: "TypeScript" + + + +$hl-keyword = #9c27b0 +$hl-blue = #1E80F0 +$hl-cyan = #17AFCA +$hl-green = #3FA33F +$hl-light-blue = #6ECDF9 +$hl-red = #EE2B29 +$hl-orange = #FB3F1B +$hl-amber = #FD8607 +$hl-text = var(--text-p1) +pre + .code:before + display: none + // 行 + .line,.params + color: $hl-text + + .line .addition + color: $hl-green + .line .deletion + color: $hl-red + + .marked + background-color: alpha(#FED542, .4) + padding: 2px 8px 2px 0 + border-radius: 2px + width: 100% + + .title, .attr, .attribute + color: $color-md-indigo + + // 注释 + .comment + color: var(--text-p3) + + .keyword, .meta-keyword, .javascript .function + color: $hl-keyword + + .type, .built_in, .tag .name + color: $color-md-light-blue + + .variable, .regexp, .ruby .constant, .xml .tag .title, .xml .pi, .xml .doctype, .html .doctype, .css .id, .css .class, .css .pseudo + color: $hl-amber + + .number, .preprocessor, .literal, .constant + color: $hl-amber + + .class, .ruby .class .title, .css .rules .attribute + color: $color-md-orange + + .string, .meta-string + color: darken($color-md-green, 10%) + + .value, .inheritance, .header, .ruby .symbol, .xml .cdata + color: $color-md-green + + .css .hexcolor + color: #66cccc + + .function, .python .decorator, .python .title, .ruby .function .title, .ruby .title .keyword, .perl .sub, .javascript .title, .coffeescript .title + color: #6699cc + + +.highlight.html,.highlight.css,.highlight.less,.highlight.stylus + .line + .tag .name, .selector-tag + color: $hl-red + .selector-class, .selector-attr + color: $hl-amber + .attribute + color: $color-md-indigo + .number + color: $hl-cyan + + +.highlight.objc,.highlight.objectivec,.highlight.swift,.highlight.c + .line + .meta + color: $hl-keyword + .meta-string,.string + color: $hl-orange + .class + color: $hl-text + .title + color: $hl-blue + .comment + color: $hl-green + +.highlight.json + .line + .attr + color: #E24F5A + .literal + color: $color-md-indigo + +.highlight.yaml + .line + .attr + color: #E24F5A diff --git a/source/css/_layout/index.styl b/source/css/_layout/index.styl new file mode 100644 index 0000000..b29a08b --- /dev/null +++ b/source/css/_layout/index.styl @@ -0,0 +1,4 @@ +@import 'partial/*' +@import 'tag-plugins/*' +@import 'sidebar/*' +@import 'pages/*' diff --git a/source/css/_layout/layout.styl b/source/css/_layout/layout.styl new file mode 100644 index 0000000..a3a6231 --- /dev/null +++ b/source/css/_layout/layout.styl @@ -0,0 +1,79 @@ +.l_body + display: flex + margin: auto + padding: 0 $gap + justify-content: center + +.l_body .l_left + z-index: 8 + width: $sidebar + flex-shrink: 0 + height 100vh + position: sticky + position: -webkit-sticky + top: 0 + +.l_body .l_main + flex-shrink: 1 + flex-grow: 1 + // margin: var(--gap) var(--gap) var(--gap) var(--gap_2) + // width: "calc(100% - %s)" % ($sidebar + 18 * $gap) + width: 320px + max-width: $layout-max-body-width + footer + margin-top: 4rem + margin-bottom: 2rem + +.float-panel + position: sticky + right: 0 + bottom: 2rem + float: right + z-index: 9 + display: flex + border-radius: 2rem 0 0 2rem + padding-right: 2rem + padding: 4px + overflow: hidden + background: var(--hover-block) +.sidebar-toggle.mobile + cursor: pointer + color: var(--text-p2) + background: white + padding: 0.5rem + margin-right: 1rem + border-radius: 32px + line-height: 1 + width: 2rem + height: 2rem + font-size: 13px + +.l_body.mobile.sidebar + .sidebar-toggle.mobile + background: $color-hover + color: white + + +// iPad 竖屏 +@media screen and (max-width: $device-tablet) + .mobile-only + display: block !important + .l_body + padding: 0 + .l_left + position: fixed + height: 100vh + width: 280px + transform: translateX(0 - $gap - 320px) + margin: 0 + left: 0 + background: var(--site-bg) + box-shadow: $boxshadow-card-float + .l_main + max-width: 100% + .l_body.mobile + .l_left + transition: transform .38s ease-out + .l_body.mobile.sidebar + .l_left + transform: translateX(0px) diff --git a/source/css/_layout/main.styl b/source/css/_layout/main.styl new file mode 100644 index 0000000..e12c02e --- /dev/null +++ b/source/css/_layout/main.styl @@ -0,0 +1,26 @@ +.l_main + position: relative + header + display: none + margin: $gap * 2 $gap $gap + padding: 0.25rem + background: var(--block) + border-radius: 8px + .logo-wrap + margin: 0.5rem 1rem + .img + width: 32px + height: 32px + display: none + .title + font-size: 1.5rem + +// pc上右边顶部留白 +@media screen and (min-width: $device-tablet) + .l_main + margin-top: $gap * 2 + +// 移动端显示主导航栏 +@media screen and (max-width: $device-tablet) + .l_main.list header + display: block diff --git a/source/css/_layout/md.styl b/source/css/_layout/md.styl new file mode 100644 index 0000000..df5e6ba --- /dev/null +++ b/source/css/_layout/md.styl @@ -0,0 +1,83 @@ +article.md + max-width: 100% + padding: 1rem + overflow: hidden + color: var(--text-p1) + line-height: 1.7 + +article.md.content + margin-bottom: $gap * 2 + +// titles +article.md + h1.article-title + margin-top: $gap * 0.5 + line-height: 1.2 + h1,h2,h3,h4,h5,h6 + line-height: 1.8 + color: var(--text-p0) + &:hover + a.headerlink:before + opacity: 1 + a.headerlink:before + opacity: 0 + content: '#' + position: absolute + width: 0.75em + margin-left: -0.75em + h2 + margin-top: 3rem + border-bottom: 1px solid var(--block-border) + font-weight: 400 + h3 + margin-top: 3rem + margin-bottom: 0 + font-weight: 500 + h2+h3 + margin-top: 1rem + h3+h4 + margin-top: 1rem + h5 + font-size: $fs14 + h6 + font-size: $fs12 + +// a +article.md + p>a + trans1: color + &:not([class]) + font-weight: 500 + &:hover + text-decoration: underline + +// code +article.md code + color: $color-inlinecode + font-family: $ff-code + font-size: $fs14 + word-break: break-all + + +// div +article.md>div + margin: 1rem 0 +// blockquote +article.md blockquote + margin: 1rem 0 + padding: 1rem + background: var(--block) + border-left: $border-block solid $color-theme + border-radius: 0 $border-block $border-block 0 + color: var(--text-p2) + p + margin: 0.5em 0 + font-size: $fs14 + +article.md ul, article.md ol + padding-left: 2rem + +article.md img + border-radius: 4px + margin: auto + display: block diff --git a/source/css/_layout/navbar.styl b/source/css/_layout/navbar.styl new file mode 100644 index 0000000..0c1e619 --- /dev/null +++ b/source/css/_layout/navbar.styl @@ -0,0 +1,51 @@ +nav.cap + position: sticky + position: -webkit-sticky + margin-top: 1.75rem + top: -2px + display: flex + background: var(--site-bg) + padding: 0.5rem 1.25rem 0.38rem + z-index: 1 + overflow: scroll + scrollbar(0, 0) + >p + margin: 0 + a + padding: 0.5rem 0.75rem + color: var(--text-p3) + border-radius: 4px + font-weight: 600 + white-space: nowrap + trans1 background + &:hover + background: var(--hover-block) + color: var(--text-p1) + &.active + font-weight: 700 + color: inherit + +.md .tag-plugin.navbar + nav.cap + margin: 0 + padding: 1px + background: var(--block) + border-radius: 6px + a + margin: 1px + padding: 0.5em 0.75rem + &:hover + background: #fff + color: var(--text-p1) + +// 面包屑导航 +.breadcrumb-navigation + padding: $gap $gap 0 + margin-top: $gap + font-size: $fs-footnote + color: var(--text-p3) + font-weight: 500 + a.cap:hover + color: $color-cat-hover + div+div + margin-top: 2px diff --git a/source/css/_layout/pages/archives.styl b/source/css/_layout/pages/archives.styl new file mode 100644 index 0000000..3cac768 --- /dev/null +++ b/source/css/_layout/pages/archives.styl @@ -0,0 +1,15 @@ +.post-list .post-card#archive + a.post + display: inline-flex + align-items: baseline + font-size: $fs14 + margin: 0.25rem 0 + font-weight: 600 + color: var(--text-p2) + &:hover + color: $color-hover + time + font-family: $ff-code + margin-right: 1em + flex-shrink: 0; + opacity 0.5 diff --git a/source/css/_layout/pages/categories.styl b/source/css/_layout/pages/categories.styl new file mode 100644 index 0000000..c15de63 --- /dev/null +++ b/source/css/_layout/pages/categories.styl @@ -0,0 +1,16 @@ +.post-list .post-card#cats + a.cat + display: flex + font-size: $fs14 + &.child + padding-left: 2rem + font-weight: 600 + padding: 0.5rem 1rem + border-radius: $border-block + color: var(--text-p2) + &:hover + background: var(--block) + color: $color-hover + .badge + opacity 0.5 + margin-left: 4px diff --git a/source/css/_layout/pages/error.styl b/source/css/_layout/pages/error.styl new file mode 100644 index 0000000..fd48438 --- /dev/null +++ b/source/css/_layout/pages/error.styl @@ -0,0 +1,21 @@ +article.md.error-page + text-align: center + margin-top: 2rem + img#error + width: 30vw + max-height: 150px + margin-bottom: 2rem + h1 + font-size: 4rem + margin-bottom: 0 + p.what,p.why + margin: 0.5em + p.why + font-size: $fs13 + a#back + margin: 2rem 0 + display: inline-block + +@media screen and (max-width: $device-tablet) + article.md.error-page + margin-top: 4rem diff --git a/source/css/_layout/pages/friends.styl b/source/css/_layout/pages/friends.styl new file mode 100644 index 0000000..069dcfa --- /dev/null +++ b/source/css/_layout/pages/friends.styl @@ -0,0 +1,61 @@ +.friends-wrap + .group-header + margin: 1rem 0 + p + margin: 0 + p.title + font-size: 1.125rem + font-weight: 500 + p.description + font-size: $fs14 + .group-body + display: grid + grid-gap: 4px 4px + grid-template-columns: repeat(auto-fill, 96px) + margin-bottom: 2rem + +.friends-wrap .user-simple + a + margin: auto + color: var(--text-p1) + font-size: $fs12 + display: flex + flex-direction: column + align-items: center + text-align: center + line-height: 1.2 + border-radius: 4px + overflow: hidden + position: relative + background: var(--card) + img + object-fit: cover + display: block + width: 64px + height: 64px + .name + padding-top: 0.5em + +// style +.friends-wrap.round .user-simple + a + padding: 0.5rem + trans1: background + img + border-radius: 64px + &:hover + background: var(--hover-block) + +.friends-wrap.rect .user-simple + a + padding: 0 + display: block + trans1: box-shadow + img + width: 96px + height: 96px + border-radius: 0 + .name + padding: 0.5em + &:hover + box-shadow: $boxshadow-card-float diff --git a/source/css/_layout/pages/tags.styl b/source/css/_layout/pages/tags.styl new file mode 100644 index 0000000..cee53fe --- /dev/null +++ b/source/css/_layout/pages/tags.styl @@ -0,0 +1,17 @@ +.post-list .post-card#tags + a.tag + display: inline-flex + align-items: center + margin: 0.25rem 0.5rem + position: relative + font-weight: 500 + color: var(--text-p2) + &:hover + color: $color-hover + span + margin: 0 0.25rem + .name + font-size: $fs14 + .badge + opacity 0.5 + font-size: $fs12 diff --git a/source/css/_layout/partial/comments.styl b/source/css/_layout/partial/comments.styl new file mode 100644 index 0000000..02cb7e2 --- /dev/null +++ b/source/css/_layout/partial/comments.styl @@ -0,0 +1,8 @@ +.comments-wrap + padding: $gap * 2 $gap + div.cmt-body.utterances + margin: 0 -4px + + a.avatar + border-radius: 120px !important + overflow: hidden !important diff --git a/source/css/_layout/partial/cover.styl b/source/css/_layout/partial/cover.styl new file mode 100644 index 0000000..27f7a65 --- /dev/null +++ b/source/css/_layout/partial/cover.styl @@ -0,0 +1,30 @@ +.l_cover + height: 100vh + text-align: center + display: flex + flex-direction: column + justify-content: center + align-items: center + +.l_cover .cover-wrap + margin-bottom: 0 + max-width: 500px + .logo + margin-bottom: 2rem + img + object-fit: contain + max-height: 35vh + max-width: 100% + .cover-title + font-weight: 700 + font-size: 1.5rem + margin: 1rem 0 + &:first-child + font-size: 3rem + .description + margin: 1rem 0 + .start-wrap + margin: $gap * 2 0 + flex-shrink: 0 + a.start + display: inline-block diff --git a/source/css/_layout/partial/lazyload.styl b/source/css/_layout/partial/lazyload.styl new file mode 100644 index 0000000..8c284f5 --- /dev/null +++ b/source/css/_layout/partial/lazyload.styl @@ -0,0 +1,14 @@ +img + max-width 100% + &.lazyload:not(.placeholder) + transition opacity .5s ease-out 0s + &:not(.loaded) + opacity: 0 + &.loaded + opacity: 1 + if hexo-config('plugins.lazyload.blurIn') == true + transition filter .25s ease-out 0s + &:not(.loaded) + filter blur(8px) + &.loaded + filter none diff --git a/source/css/_layout/partial/paginator.styl b/source/css/_layout/partial/paginator.styl new file mode 100644 index 0000000..8bcbffd --- /dev/null +++ b/source/css/_layout/partial/paginator.styl @@ -0,0 +1,22 @@ +.posts .paginator-wrap + display: flex + justify-content: space-between + align-items: center + disable-select() + font-weight: 500 + svg.icon + font-size: 1.8rem + .paginator + text-align: center + padding: $gap + div.paginator + font-size: $fs14 + color: var(--text-p2) + a.paginator + color: $color-link + trans1: color + &.disable + pointer-events: none + opacity: 0.25 + a.paginator:hover + color: $color-hover diff --git a/source/css/_layout/partial/read_next.styl b/source/css/_layout/partial/read_next.styl new file mode 100644 index 0000000..e49458b --- /dev/null +++ b/source/css/_layout/partial/read_next.styl @@ -0,0 +1,18 @@ +.read-next-wrap + padding: $gap * 2 $gap + .body + .post-title + margin: 0.5rem 0 + line-height: 1.2 + font-size: $fs14 + color: var(--text-p2) + font-weight: 500 + a + color: inherit + &:hover + color: $color-hover + &.read + color: var(--text-p3) + font-size: $fs12 + &.unread + font-size: 1rem diff --git a/source/css/_layout/partial/references.styl b/source/css/_layout/partial/references.styl new file mode 100644 index 0000000..aa7c9ce --- /dev/null +++ b/source/css/_layout/partial/references.styl @@ -0,0 +1,16 @@ +.references-wrap + margin: $gap * 2 $gap + padding: 1rem + background: var(--block) + border-radius: $border-block + .header + font-weight: 500 + color: var(--text-p3) + margin-bottom: 1rem + .body + ul + margin: 0 + .post-title + margin: 0.5rem 0 + line-height: 1.2 + font-size: $fs13 diff --git a/source/css/_layout/partial/related_posts.styl b/source/css/_layout/partial/related_posts.styl new file mode 100644 index 0000000..4077ac7 --- /dev/null +++ b/source/css/_layout/partial/related_posts.styl @@ -0,0 +1,71 @@ +div.related-posts-wrap + padding: $gap * 2 $gap + &:empty + display: none + .related-posts + width: 100% + display: flex + margin: $gap 0 + overflow-x: scroll + disable-select() + align-items: flex-start + scrollbar(8px, 4px) + padding-bottom: 4px + a + flex-grow: 0 + flex-shrink: 0 + background: var(--card) + border-radius: 0.5rem + padding-bottom: 1rem + line-height: 1.2 + display: flex + flex-direction: column + overflow: hidden + width: 360px + opacity: 0.7 + trans1: opacity 0.5s + border: 1px solid var(--hover-block) + .img + height: 180px + overflow: hidden + img + width: 100% + height: 100% + object-fit: cover + @media screen and (max-width: $device-tablet) + width: 300px + .img + height: 150px + @media screen and (max-width: $device-mobile) + width: 300px + .title + color: var(--text-p1) + font-weight: 500 + font-size: $fs15 + margin: 1rem 1rem 0 1rem + display: -webkit-box + -webkit-box-orient: vertical + overflow: hidden + -webkit-line-clamp: 2 + .excerpt + color: var(--text-p2) + font-size: $fs13 + margin: 0.4rem 1rem 0 1rem + display: -webkit-box + -webkit-box-orient: vertical + overflow: hidden + -webkit-line-clamp: 3 + &:hover + opacity: 1 + a+a + margin-left: $gap + + +// // iPad 竖屏 +// @media screen and (max-width: $device-tablet) +// section.related-posts-wrap +// .related-posts +// a +// min-width: 280px +// .img +// height: 120px diff --git a/source/css/_layout/post_list.styl b/source/css/_layout/post_list.styl new file mode 100644 index 0000000..39495c1 --- /dev/null +++ b/source/css/_layout/post_list.styl @@ -0,0 +1,107 @@ +// list +.post-list + margin: 1rem + .card-title,.list-title + font-weight: 600 + color: var(--text-meta) + font-family: $ff-code + line-height: 1.2 + .list-title + margin: 2rem 1rem 0rem + font-size: 1.5rem + .card-title + padding-bottom: 0.5rem + font-size: 1.2rem + +// card +.post-list .post-card + display: block + margin: 1rem 0 + color: var(--text-p2) + border-radius: $border-card + box-shadow: 0 2px 8px 0px rgba(0, 0, 0, 0.02) + trans1 box-shadow + overflow: hidden + background: var(--card) + .meta.cap + margin-bottom: 0.5rem + span+span + margin-left: 0.5rem +.post-list .post-card:hover + box-shadow: 0 2px 8px 0px rgba(0, 0, 0, 0.04), 0 4px 16px 0px rgba(0, 0, 0, 0.04) + .logo img + transform: scale(1.1) + .excerpt .readmore + color: $color-link + +// common article +.post-list article + padding: 1rem + +// posts +.post-list .post-card + .post-title + font-weight: 500 + margin: .5em 0 + line-height: 1.2 + font-size: $fs-h3 + border-bottom: none + color: var(--text-p1) + trans1 color + .excerpt + font-size: $fs14 + .post-cover-wrap + overflow: hidden + margin-left: 0 - 1.5 * $gap + margin-top: 0 - 1.5 * $gap + margin-bottom: 1.25 * $gap + width: "calc(100% + 3 * %s)" % $gap + .post-cover + background-position: center + background-size: cover + height: 320px + @media screen and (max-width: 900px) + height: 280px + @media screen and (max-width: $device-tablet) + height: 320px + @media screen and (max-width: $device-mobile) + height: 280px + @media screen and (max-width: $device-mobile-l) + height: 240px + @media screen and (max-width: $device-mobile-m) + height: 200px + trans1: transform 1s +.post-list .post-card.post:hover + .post-title + color: $color-hover + .post-cover + transform: scale(1.04) + +// wiki +.post-list .post-card.wiki article + display: flex + flex-wrap: wrap + trans1 box-shadow + justify-content: center + + +.post-list .post-card.wiki article .logo + display: flex + width: 180px + margin: 1rem + align-items: center + img + object-fit: contain + trans1 transform 0.75s +.post-list .post-card.wiki article .excerpt + margin: 1rem + min-width: 220px + flex: 1 + overflow: hidden + word-wrap: break-word + .title + font-weight: 600 + font-size: $fs-h3 + >p + margin: 0.5rem 0 + font-size: $fs14 diff --git a/source/css/_layout/sidebar.styl b/source/css/_layout/sidebar.styl new file mode 100644 index 0000000..adb2c9f --- /dev/null +++ b/source/css/_layout/sidebar.styl @@ -0,0 +1,133 @@ +.l_left .wrap + display: flex + flex-direction: column + height: "calc(100% - 4 * %s)" % $gap + margin-top: $gap * 2 + padding: $gap + @media screen and (max-width: $device-tablet) + height: "calc(100% - 2 * %s)" % $gap + margin-top: 0 + +.logo-wrap + margin: $gap 0 + display: flex + align-items: center + color: var(--text-p0) + &:hover + color: var(--text-p0) + .img + width: 40px + height: 40px + flex-shrink: 0 + border-radius: 20px + overflow: hidden + margin-right: 1rem + img + object-fit: cover + .title + padding-top: 2px + font-size: 1.75rem + font-weight: 900 + color: inherit + font-family: $ff-logo + +nav.menu + margin-top: 0 + background: var(--block) + border-radius: 6px + disable-select() + display: flex + padding: 1px + flex-wrap: wrap + &::-webkit-scrollbar + display: none + &::-webkit-scrollbar-track-piece + background: transparent + &::-webkit-scrollbar-thumb + display: none + a.nav-item + text-overflow: ellipsis + word-break: keep-all + margin: 1px + border-radius: 4px + font-size: $fs14 + font-weight: 500 + trans2: color background + overflow: hidden + span + color: var(--text-p3) + display: block + padding: 6px 12px + &.active span, &:hover span + color: var(--text-p1) + background: var(--card) + +.l_left .widgets + margin: $gap 0 + overflow: scroll + flex-grow: 1 + scrollbar(0, 0) + .widget-wrap + margin: 1rem 0 2rem 0 + .widget-header + display: flex + font-size: 1rem + color: var(--text-meta) + justify-content: space-between + align-items: center + font-weight: 600 + position: sticky + position: -webkit-sticky + top: -2px + background: var(--site-bg) + padding: 2px 0 + z-index 1 + .name + font-size: 1rem + .cap-action + hover-block 4px 4px + line-height: 0 + color: var(--text-meta) + trans2: color background + .icon + fill: var(--text-meta) + &:hover + color: $color-hover + .icon + fill: $color-hover + + .widget-body + margin: 0.5rem 0 + font-size: $fs14 + color: var(--text-p2) + p + margin-top: 0.5em + margin-bottom: 0.5em + >a + &:not([class]) + font-weight: 500 + &:hover + text-decoration: underline + + + +.l_left .footer + margin-top: 0 + margin-bottom: 1rem + line-height: 0 + .social-wrap + display: grid + grid-gap: $gap * 0.5 $gap * 0.5 + grid-template-columns: repeat(auto-fill, 32px) + a + display: inline-block + background: var(--card) + padding: 4px + border-radius: 4px + filter: grayscale(100%) + overflow: hidden + trans1: box-shadow + &:hover + color: $color-hover + filter: grayscale(0%) + box-shadow: $boxshadow-float diff --git a/source/css/_layout/sidebar/recent.styl b/source/css/_layout/sidebar/recent.styl new file mode 100644 index 0000000..408d81a --- /dev/null +++ b/source/css/_layout/sidebar/recent.styl @@ -0,0 +1,10 @@ +.widgets + .post-title + margin: 0.5rem 0 + line-height: 1.2 + font-size: $fs14 + font-weight: 500 + a + color: inherit + &:hover + color: $color-hover diff --git a/source/css/_layout/sidebar/toc.styl b/source/css/_layout/sidebar/toc.styl new file mode 100644 index 0000000..9eb0a91 --- /dev/null +++ b/source/css/_layout/sidebar/toc.styl @@ -0,0 +1,74 @@ +// toc padding +#toc .widget-body + line-height: 1.2 + .toc + padding: 0 + margin: 0 + padding-left: 0.25rem + .toc-item .toc-link + padding: 0.5rem 0 0.5rem 1rem + font-weight: 500 + font-size: $fs13 + color: var(--text-p2) + .toc-child .toc-item .toc-link + padding: 0.25rem 0 0.25rem 1.8rem + font-weight: 400 + color: var(--text-p2) + .toc-child .toc-child .toc-item .toc-link + padding-left: 2.6rem + font-size: $fs12 + color: var(--text-p3) + .toc-child .toc-child .toc-child .toc-item .toc-link + padding-left: 3.4rem + .toc:only-child + .toc-item .toc-link + padding-left: 0.5rem + .toc-child .toc-item .toc-link + padding-left: 1.3rem + .toc-child .toc-child .toc-item .toc-link + padding-left: 2.1rem + .toc-child .toc-child .toc-child .toc-item .toc-link + padding-left: 2.9rem + + +#toc .toc-item + color: var(--text-p2) + font-size: $fs12 + padding: 0 + list-style: none + &.active + color: $color-theme + border-left-color: @color + .toc-child .toc-item + padding: 0 +#toc a.toc-link + color: inherit + display: block + line-height: 1.2 + border-radius: 4px + &:hover + background: var(--hover-block) + &.active + color: var(--theme-highlight) !important + +#toc .doc-tree + border-left: 2px solid var(--hover-block) + a.doc-tree-link + color: var(--text-p3) + padding: 0.5rem + display: block + border-top-right-radius: 4px + border-bottom-right-radius: 4px + font-size: $fs12 + font-weight: 500 + &.active + color: var(--text-p2) + font-size: $fs14 + &:hover + background: var(--hover-block) + +#toc .widget-body.wiki + .doc-tree.active + border-color: var(--text-meta) + .doc-tree.active:only-child + border-color: var(--hover-block) diff --git a/source/css/_layout/tag-plugins/about.styl b/source/css/_layout/tag-plugins/about.styl new file mode 100644 index 0000000..937a12d --- /dev/null +++ b/source/css/_layout/tag-plugins/about.styl @@ -0,0 +1,58 @@ +.tag-plugin.about + background: var(--block) + border-radius: 6px + padding: 2rem + .about-header + display flex + flex-direction: row-reverse + justify-content: space-between + flex-wrap: wrap + img + object-fit: contain + >img + margin: auto 0 + >p + font-size: $fs12 + font-weight: 500 + color: var(--text-p3) + padding-top: 0.75rem + strong:first-child + font-size: 3rem + font-weight: 700 + color: var(--text-p1) + margin-right: 0.75rem + .avatar + display: inline-flex + margin: 0 1rem + // flex-shrink: 0 + .about-body + >p + font-size: $fs14 + line-height: 1.5 + .tag-plugin.navbar:last-child + // margin: 0 -0.75rem -0.75rem + nav.cap + padding: 0 + background: none + a + margin: 0 + padding: 0 + color: var(--text-p1) + color: $color-link + &:hover + color: $color-hover + background: none + a+a + margin-left: 1rem + .about-header+.about-body + margin-top: 1.5rem + +@media screen and (max-width: $device-mobile) + .tag-plugin.about + background: none + padding: 1rem + .about-header + .avatar + margin: 1rem auto + p + width 100% diff --git a/source/css/_layout/tag-plugins/checkbox.styl b/source/css/_layout/tag-plugins/checkbox.styl new file mode 100644 index 0000000..ad1ad53 --- /dev/null +++ b/source/css/_layout/tag-plugins/checkbox.styl @@ -0,0 +1,178 @@ +.md .checkbox + display: flex + align-items: center + margin: 0 + font-size: $fs15 + input + -webkit-appearance: none + -moz-appearance: none + -ms-appearance: none + -o-appearance: none + appearance: none + position: relative + height: 16px + width: 16px + cursor: pointer + display: inline-block + outline: none + border-radius: 2px + flex-shrink: 0 + margin-right: 8px + if hexo-config('tag_plugins.checkbox.interactive') != true + pointer-events: none + /* Checkbox */ + input[type=checkbox] + &:before, &:after + position: absolute + content: "" + background: var(--site-bg) + &:before + left: 1px + top: 5px + width: 0px + height: 2px + transform: rotate(45deg) + -webkit-transform: rotate(45deg) + -moz-transform: rotate(45deg) + -ms-transform: rotate(45deg) + -o-transform: rotate(45deg) + &:after + right: 7px + bottom: 3px + width: 2px + height: 0px + transform: rotate(40deg) + -webkit-transform: rotate(40deg) + -moz-transform: rotate(40deg) + -ms-transform: rotate(40deg) + -o-transform: rotate(40deg) + &:checked + &:before + left: 0px + top: 7px + width: 6px + height: 2px + &:after + right: 3px + bottom: 1px + width: 2px + height: 10px + &[symbol=minus] input[type=checkbox] + &:before + transform: rotate(0) + left: 1px + top: 5px + width: 0px + height: 2px + &:after + transform: rotate(0) + left: 1px + top: 5px + width: 0px + height: 2px + &:checked + &:before + left: 1px + top: 5px + width: 10px + height: 2px + &:after + left: 1px + top: 5px + width: 10px + height: 2px + &[symbol=plus] input[type=checkbox] + &:before + transform: rotate(0) + left: 1px + top: 5px + width: 0px + height: 2px + &:after + transform: rotate(0) + left: 5px + top: 1px + width: 2px + height: 0px + &:checked + &:before + left: 1px + top: 5px + width: 10px + height: 2px + &:after + left: 5px + top: 1px + width: 2px + height: 10px + &[symbol=times] input[type=checkbox] + &:before + transform: rotate(45deg) + left: 3px + top: 1px + width: 0px + height: 2px + &:after + transform: rotate(135deg) + right: 3px + top: 1px + width: 0px + height: 2px + &:checked + &:before + left: 1px + top: 5px + width: 10px + height: 2px + &:after + right: 1px + top: 5px + width: 10px + height: 2px + /* Radio */ + input[type=radio] + border-radius: 50% + transform: translateY(-1px) + &:before + content: "" + display: block + width: 8px + height: 8px + border-radius: 50% + margin: 2px + transform: scale(0) + &:checked:before + transform: scale(1) + /* Colors */ + input + border: 2px solid var(--theme) + &[type=checkbox]:checked + background: var(--theme) + &[type=radio]:checked:before + background: var(--theme) + + + +.tag-plugin.checkbox + --theme: $color-theme + +.tag-plugin.checkbox[color='red'] + --theme: mix($c-red, $c-card-light, 90) + +.tag-plugin.checkbox[color='orange'] + --theme: mix($c-orange, $c-card-light, 90) + +.tag-plugin.checkbox[color='yellow'] + --theme: mix($c-yellow, $c-card-light, 90) + +.tag-plugin.checkbox[color='green'] + --theme: mix($c-green, $c-card-light, 90) + +.tag-plugin.checkbox[color='cyan'] + --theme: mix($c-cyan, $c-card-light, 90) + +.tag-plugin.checkbox[color='blue'] + --theme: mix($c-blue, $c-card-light, 100) + +.tag-plugin.checkbox[color='purple'] + --theme: mix($c-purple, $c-card-light, 90) diff --git a/source/css/_layout/tag-plugins/common.styl b/source/css/_layout/tag-plugins/common.styl new file mode 100644 index 0000000..b15986d --- /dev/null +++ b/source/css/_layout/tag-plugins/common.styl @@ -0,0 +1,78 @@ +.tag-plugin + --theme: var(--block-border) + --theme-bg: var(--block) + +.tag-plugin[color='red'] + --theme: mix($c-red, $c-card-light, 40) + --theme-bg: mix($c-red, $c-card-light, 10) + +.tag-plugin[color='orange'] + --theme: mix($c-orange, $c-card-light, 40) + --theme-bg: mix($c-orange, $c-card-light, 10) + +.tag-plugin[color='yellow'] + --theme: mix($c-yellow, $c-card-light, 40) + --theme-bg: mix($c-yellow, $c-card-light, 10) + +.tag-plugin[color='green'] + --theme: mix($c-green, $c-card-light, 40) + --theme-bg: mix($c-green, $c-card-light, 10) + +.tag-plugin[color='cyan'] + --theme: mix($c-cyan, $c-card-light, 40) + --theme-bg: mix($c-cyan, $c-card-light, 10) + +.tag-plugin[color='blue'] + --theme: mix($c-blue, $c-card-light, 40) + --theme-bg: mix($c-blue, $c-card-light, 10) + +.tag-plugin[color='purple'] + --theme: mix($c-purple, $c-card-light, 40) + --theme-bg: mix($c-purple, $c-card-light, 10) + + +.tag-plugin[color='white'] + --theme-bg: white + + +.tag-plugin[color='dark'] + --theme-bg: mix(black, $c-card-light, 75) + color: var(--card) !important + +body[theme='dark'] + .tag-plugin[color='red'] + --theme: mix($c-red, $c-card-dark, 40) + --theme-bg: mix($c-red, $c-card-dark, 10) + + .tag-plugin[color='orange'] + --theme: mix($c-orange, $c-card-dark, 40) + --theme-bg: mix($c-orange, $c-card-dark, 10) + + .tag-plugin[color='yellow'] + --theme: mix($c-yellow, $c-card-dark, 40) + --theme-bg: mix($c-yellow, $c-card-dark, 10) + + .tag-plugin[color='green'] + --theme: mix($c-green, $c-card-dark, 40) + --theme-bg: mix($c-green, $c-card-dark, 10) + + .tag-plugin[color='cyan'] + --theme: mix($c-cyan, $c-card-dark, 40) + --theme-bg: mix($c-cyan, $c-card-dark, 10) + + .tag-plugin[color='blue'] + --theme: mix($c-blue, $c-card-dark, 40) + --theme-bg: mix($c-blue, $c-card-dark, 10) + + .tag-plugin[color='purple'] + --theme: mix($c-purple, $c-card-dark, 40) + --theme-bg: mix($c-purple, $c-card-dark, 10) + + + .tag-plugin[color='white'] + --theme-bg: white + color: var(--card) + + .tag-plugin[color='dark'] + --theme-bg: mix(black, $c-card-dark, 75) + color: var(--text-p0) !important diff --git a/source/css/_layout/tag-plugins/folding.styl b/source/css/_layout/tag-plugins/folding.styl new file mode 100644 index 0000000..23ead8f --- /dev/null +++ b/source/css/_layout/tag-plugins/folding.styl @@ -0,0 +1,62 @@ +details + display: block + padding: 1rem + margin: 1rem 0 + border-radius: $border-block + font-size: $fs15 + background: var(--theme-bg) + border: 1px solid var(--theme) + summary + cursor: pointer + padding: 1rem + margin: 0 - 1rem + border-radius: $border-block + color: var(--text-p2) + font-size: $fs14 + font-weight: 500 + position: relative + line-height: normal + outline: none + > + p,h1,h2,h3,h4,h5,h6 + display: inline + border-bottom: none !important + &:hover + color: var(--text-p0) + &:after + position: absolute + content: '+' + text-align: center + top: 50% + transform: translateY(-50%) + right: 1rem + + +details[open] + >summary + border-bottom: 1px solid var(--theme) + border-bottom-left-radius: 0 + border-bottom-right-radius: 0 + color: var(--text-p1) + margin-bottom: 0 + &:hover + &:after + content: '-' + >div.body + padding: 1rem + margin: 0 - 1rem + margin-top: 0 + background: var(--card) + border-bottom-left-radius: $border-block + border-bottom-right-radius: $border-block + font-size: $fs15 + inside-box() + +details[codeblock]>div.body + padding: 0 + background: transparent + .highlight + border: none + border-radius: 0 + background: transparent + margin: 0 diff --git a/source/css/_layout/tag-plugins/frame.styl b/source/css/_layout/tag-plugins/frame.styl new file mode 100644 index 0000000..6cbfc19 --- /dev/null +++ b/source/css/_layout/tag-plugins/frame.styl @@ -0,0 +1,55 @@ +.md .frame-wrap + position: relative + overflow: hidden + margin: 0 auto + max-width: 100% + display: flex + flex-direction: column + align-items: center + img,video + border-radius: 0 +.md .frame-wrap .frame + z-index: 1 + display: block + position: absolute; + background-size: 100%; + background-repeat: no-repeat; + overflow: hidden; + +.md .img-wrap .frame-wrap + &[focus] + height: auto + +.md .frame-wrap + &#iphone11 + img,video + width: 287px + margin-top: 19px + margin-bottom: 20px + .frame + background-image: url(https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@3/img/frame/iphone11.svg); + width: 329px + height: 658px + &[focus='top'] + img,video + margin-bottom: 0 !important + &:not([focus='bottom']) + .frame + top: 0 + &[focus='bottom'] + img,video + bottom: 0 + margin-top: 0 !important + .frame + bottom: 0 + +@media screen and (max-width: $device-mobile) + .md .frame-wrap + &#iphone11 + img,video + width: 208px + margin-top: 13px + margin-bottom: 14px + .frame + width: 238px + height: 476px diff --git a/source/css/_layout/tag-plugins/ghcard.styl b/source/css/_layout/tag-plugins/ghcard.styl new file mode 100644 index 0000000..e3d30ef --- /dev/null +++ b/source/css/_layout/tag-plugins/ghcard.styl @@ -0,0 +1,3 @@ +a.ghcard + display: inline-block + line-height: 0 diff --git a/source/css/_layout/tag-plugins/image.styl b/source/css/_layout/tag-plugins/image.styl new file mode 100644 index 0000000..2c6f909 --- /dev/null +++ b/source/css/_layout/tag-plugins/image.styl @@ -0,0 +1,35 @@ +.img-wrap + margin-top: 1rem + margin-bottom: 1rem + .img-bg + line-height: 0 + text-align: center + border-radius: 4px + img + display: inline-block + object-fit: contain + .image-meta + display: flex + justify-content: space-between + align-items: flex-start + padding-top: 0.5rem + .image-caption + display: inline-block + font-size: $fs-footnote + line-height: 1.4 + color: var(--text-p3) + flex-grow: 1 + &:empty + display: none + &.left + text-align: left + &.center + text-align: center + .image-download + margin-left: 4px + padding: 4px + line-height: 0 + border-radius: 4px + trans2: color background + &:hover + background: var(--hover-block) diff --git a/source/css/_layout/tag-plugins/link.styl b/source/css/_layout/tag-plugins/link.styl new file mode 100644 index 0000000..3d1b33c --- /dev/null +++ b/source/css/_layout/tag-plugins/link.styl @@ -0,0 +1,70 @@ +.md .tag.link + margin-top: 1em + margin-bottom: 1em + +.md .link-card + margin-right: 1em + background: var(--card) + display: inline-flex + justify-content: space-between + align-items: center + cursor: pointer + min-width 250px + max-width: 100% + box-shadow: $boxshadow-card + transition: box-shadow + @media screen and (max-width: $device-mobile-l) + max-width: 100% + width: 100% + border-radius: 8px + &:hover + box-shadow: $boxshadow-float, $boxshadow-card-float + + +.md .link-card + div.left,div.right + pointer-events: none + div.right + width: 54px + height: 54px + margin: 12px + overflow: hidden + flex-shrink: 0 + position: relative + i + font-size: 32px + line-height: 48px + margin-left: 4px + img + display: block + position: absolute + border-radius: $border-card / 4 + top: 50% + left: 50% + transform: translate(-50%, -50%) + div.left + overflow: hidden + margin-left: 16px + span + margin: 0 + display: block + txt-ellipsis() + span.title + font-weight: 500 + color: var(--text-p1) + font-size: $fs14 + span.url + flex-shrink: 0 + color: var(--text-p2) + font-size: $fs13 + +.md .link-group + display: grid + grid-template-columns: 1fr 1fr + @media screen and (max-width: $device-mobile-l * 2) + grid-template-columns: 1fr + grid-gap: $gap + .tag.link + margin: 0 + .link-card + width: 100% diff --git a/source/css/_layout/tag-plugins/note.styl b/source/css/_layout/tag-plugins/note.styl new file mode 100644 index 0000000..2b7b103 --- /dev/null +++ b/source/css/_layout/tag-plugins/note.styl @@ -0,0 +1,16 @@ +.md div.note + $border-block = 4px + position: relative + margin-top: 1rem + margin-bottom: 1rem + padding: 1rem + border-radius: $border-block + font-size: $fs15 + background: var(--theme-bg) + border: 1px solid var(--theme) + color: var(--text-p1) + div.title + inside-box: $fs15 + margin-bottom: 0.5rem + div.body + inside-box: $fs14 diff --git a/source/css/_layout/tag-plugins/site-card.styl b/source/css/_layout/tag-plugins/site-card.styl new file mode 100644 index 0000000..efd6b7a --- /dev/null +++ b/source/css/_layout/tag-plugins/site-card.styl @@ -0,0 +1,68 @@ +.site-card-group + display: grid + grid-gap: $gap $gap + grid-template-columns: repeat(auto-fill, "calc((100% - 3 * %s) / 4)" % $gap) + @media screen and (max-width: $device-laptop) + grid-template-columns: repeat(auto-fill, "calc((100% - 2 * %s) / 3)" % $gap) + @media screen and (max-width: $device-mobile) + grid-template-columns: repeat(auto-fill, "calc((100% - 1 * %s) / 2)" % $gap) + margin-bottom: 2rem + +.site-card-group .site-card + line-height: 1.2 + disable-select() + color: var(--text-p1) + .img + width: 100% + height 120px + @media screen and (max-width: $device-mobile) + height 100px + overflow: hidden + border-radius: $border-card * 0.5 + box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.2) + background: var(--color-block) + img + width: 100% + height 100% + transition: transform 2s ease + object-fit: cover + + .info + margin-top: $gap * 0.5 + img + width: 32px + height: 32px + border-radius: 16px + float: left + margin-right: 8px + margin-top: 2px + span + display: block + .title + font-weight: 600 + color: var(--text-p1) + font-size: $fs15 + margin-top: 1px + color: var(--color-p) + display: -webkit-box + -webkit-box-orient: vertical + overflow: hidden + -webkit-line-clamp: 1 + + .desc + font-size: $fs12 + color: var(--text-p2) + margin-top: 2px + word-wrap: break-word; + color: var(--color-meta) + display: -webkit-box + -webkit-box-orient: vertical + overflow: hidden + -webkit-line-clamp: 2 + .img + trans1 box-shadow + &:hover + .img + box-shadow: $boxshadow-float, $boxshadow-card-float + .info .title + color: $color-hover diff --git a/source/css/_layout/tag-plugins/timeline.styl b/source/css/_layout/tag-plugins/timeline.styl new file mode 100644 index 0000000..cef2b55 --- /dev/null +++ b/source/css/_layout/tag-plugins/timeline.styl @@ -0,0 +1,82 @@ +div.timeline + position: relative + display: block + margin: 1rem 0 + padding-top: 1rem + padding-bottom: 1rem + &:before + content: '' + z-index: 0 + position: absolute + background: var(--block-border) + width: 2px + left: 16px + top: 1rem + bottom: 1rem + svg.top, svg.bottom + position: absolute + z-index: 1 + fill: var(--block-border) + height 16px + width: 16px + margin-left: 9px + svg.top + margin-top: -1rem + svg.bottom + margin-bottom: 1rem + +div.timenode + position: relative + background: var(--card) + border: 1px solid var(--block-border) + border-radius: 6px + margin-top: 1rem + margin-bottom: 1rem + font-size: $fs14 + .header + line-height: 1.2 + background: var(--block) + border-top-left-radius: 5px + border-top-right-radius: 5px + border-bottom: 1px solid var(--block-border) + display: flex + justify-content: space-between + align-items: center + font-size: $fs14 + span + font-weight: 500 + color: var(--text-p1) + padding: 0.8rem 16px + a + visibility: hidden + margin-left: 4px + padding: 0.4rem 8px + margin-right: 8px + line-height: 0 + border-radius: 4px + color: var(--text-p1) + &:hover + color: $color-link + .body + padding: 0.5rem 1rem + p,.highlight,ol,ul + margin: 0.5rem 0 + li + font-size: $fs14 + +div.timenode:hover + .header a + visibility: visible + +// div.timeline:hover +// &:before +// background: var(--block-border) +// svg.top, svg.bottom +// fill: var(--block-border) +// div.timenode:hover +// border-color: var(--block-border) +// .header +// background: var(--block-border) +// border-color: var(--block-border) +// a +// visibility: visible diff --git a/source/css/_plugins/index.styl b/source/css/_plugins/index.styl new file mode 100644 index 0000000..3391e80 --- /dev/null +++ b/source/css/_plugins/index.styl @@ -0,0 +1,3 @@ +// 根据主题配置加载 +if hexo-config('plugins.swiper.enable') + @import 'swiper' diff --git a/source/css/_plugins/swiper.styl b/source/css/_plugins/swiper.styl new file mode 100644 index 0000000..53ab211 --- /dev/null +++ b/source/css/_plugins/swiper.styl @@ -0,0 +1,48 @@ +:root + --swiper-theme-color: $color-mac-cyan !important +.swiper-container + width: 100% + border-radius: 4px +.swiper-container:not(.swiper-container-initialized) + display: none +div.swiper-slide + text-align: center + display: -webkit-box + display: -ms-flexbox + display: -webkit-flex + display: flex + align-self: center + -webkit-box-pack: center + -ms-flex-pack: center + -webkit-justify-content: center + justify-content: center + -webkit-box-align: center + -ms-flex-align: center + -webkit-align-items: center + align-items: center + width: 50% + img + border-radius: 4px + +.swiper-container[width='max'] div.swiper-slide + width: 100% + +.swiper-container[width='min'] div.swiper-slide + width: 25% + +.swiper-button-prev,.swiper-button-next + padding: 1rem 0.5rem + margin-top: -2rem !important + border-radius: 4px + background: alpha(white, 0.25) + trans1 background + --swiper-theme-color: black !important + @supports (backdrop-filter: blur(20px)) + background: alpha(white, 0.5) + backdrop-filter: saturate(200%) blur(20px) + &:after + font-size: 1.2rem !important + font-weight: 700 !important + &:hover + background: white + --swiper-theme-color: $color-hover !important diff --git a/source/css/main.styl b/source/css/main.styl new file mode 100644 index 0000000..9f560a8 --- /dev/null +++ b/source/css/main.styl @@ -0,0 +1,16 @@ +// 常量 +@import '_defines/base' +@import '_defines/const' + +// 自定义 +@import '_custom' + +// 含自定义参数的常量 +@import '_defines/theme' +@import '_defines/func' + +// 布局 +@import '_layout/*' + +// 可选插件 +@import '_plugins/index' diff --git a/source/js/issues.js b/source/js/issues.js new file mode 100644 index 0000000..deb0def --- /dev/null +++ b/source/js/issues.js @@ -0,0 +1,185 @@ +const IssuesAPI = { + requestIssuesAPI(url, callback, timeout) { + let retryTimes = 10; + function request() { + return new Promise((resolve, reject) => { + let status = 0; // 0 等待 1 完成 2 超时 + let timer = setTimeout(() => { + if (status === 0) { + status = 2; + timer = null; + reject('请求超时'); + if (retryTimes == 0) { + timeout(); + } + } + }, 5000); + fetch(url).then(function(response) { + if (status !== 2) { + clearTimeout(timer); + resolve(response); + timer = null; + status = 1; + } + if (response.ok) { + return response.json(); + } + throw new Error('Network response was not ok.'); + }).then(function(data) { + retryTimes = 0; + callback(data); + }).catch(function(error) { + if (retryTimes > 0) { + retryTimes -= 1; + setTimeout(() => { + request(); + }, 5000); + } else { + timeout(); + } + }); + }); + } + request(); + }, + parseIssueStrToJson(str) { + let jsonStr = str.match(/```json[\s|\S]*```/); + if (jsonStr && jsonStr.length > 0) { + jsonStr = jsonStr[0]; + } + if (jsonStr) { + jsonStr = jsonStr.split('```json')[1].split('```')[0]; + if (jsonStr) { + return JSON.parse(jsonStr); + } + } + return undefined; + }, + groupIssuesData(cfg, data) { + var groups = new Object(); + if (data.length > 0) { + if (cfg.group != undefined) { + const arr = cfg.group.split('='); + if (arr.length > 1) { + const groupKey = arr[0]; + let groupList = arr[1]; + if (groupKey && groupList) { + groupList = groupList.split(','); + } + cfg.group = groupList; + for (i = 0; i < data.length; i++) { + const obj = this.parseIssueStrToJson(data[i].body); + if (obj && (groupKey in obj)) { + let tmp = obj[groupKey]; + tmp = tmp.replace(', ', ',').split(','); + for (var j = 0; j < tmp.length; j++) { + if (groupList.includes(tmp[j])) { + let arr = groups[tmp[j]]; + if (arr == undefined) { + arr = new Array(); + } + arr.push(obj); + groups[tmp[j]] = arr; + } + } + } + } + } + } else { + cfg.group = ['']; + for (i = 0; i < data.length; i++) { + const obj = this.parseIssueStrToJson(data[i].body); + if (obj) { + let arr = groups['']; + if (arr == undefined) { + arr = new Array(); + } + arr.push(obj); + groups[''] = arr; + } + } + } + } + return groups; + }, + getIssuesAPIForSites(cfg) { + const el = $(cfg.el)[0]; + $(el).append('

正在加载

'); + this.requestIssuesAPI(cfg.api, function(data) { + $(el).find('.loading').remove(); + const dt = IssuesAPI.groupIssuesData(cfg, data); + const groupTitles = Object.keys(dt); + cfg.group.forEach((groupTitle, i) => { + const issues = dt[groupTitle]; + if (issues && issues.length > 0) { + if (groupTitle.length > 0) { + $(el).append('

' + groupTitle + '

'); + } else if (name == '' && groupTitles.length > 1) { + $(el).append('

' + '未分组' + '

'); + } + $(el).append('
'); + // layout items + for (j = 0; j < issues.length; j++) { + const issue = issues[j]; + let imgTag = ''; + if (issue.screenshot && issue.screenshot.length > 0) { + imgTag = '
'; + } else { + imgTag = '
'; + } + let infoTag = '
'; + if (issue.avatar && issue.avatar.length > 0) { + infoTag += ''; + } + infoTag += '' + issue.title + '' + issue.description + '
'; + const cardTag = '
' + imgTag + infoTag + '
'; + $(el).find('.site-card-group.' + i).append(cardTag); + } + } + }); + }, function() { + $(el).find('.loading i').remove(); + $(el).find('.loading p').text('加载失败,请稍后重试。'); + }); + }, + getIssuesAPIForTimeline(cfg) { + const el = $(cfg.el)[0]; + $(el).append('

正在加载

'); + this.requestIssuesAPI(cfg.api, function(data) { + $(el).find('.loading').remove(); + if (data.length > 0) { + for (i = 0; i < data.length; i++) { + const a = '  ' + data[i].comments + ''; + const header = '

' + data[i].title + a + '

'; + const body = '

' + data[i].body + '

'; + const tag = '
' + header + body + '
'; + $(el).append(tag); + } + } + }, function() { + $(el).find('.loading i').remove(); + $(el).find('.loading p').text('加载失败,请稍后重试。'); + }); + }, + request() { + const els = document.getElementsByClassName('issues-wrap'); + for (var i = 0; i < els.length; i++) { + const el = els[i]; + const api = el.getAttribute('api'); + const group = el.getAttribute('group'); + var cfg = new Object(); + cfg.class = el.getAttribute('class'); + cfg.el = el; + cfg.api = api; + cfg.group = group; + if (cfg.class.split(' ').includes('sites')) { + this.getIssuesAPIForSites(cfg); + } else if (cfg.class.split(' ').includes('timeline')) { + this.getIssuesAPIForTimeline(cfg); + } + } + } +}; +$(function () { + IssuesAPI.request(); +}); \ No newline at end of file diff --git a/source/js/main.js b/source/js/main.js new file mode 100644 index 0000000..d12fcec --- /dev/null +++ b/source/js/main.js @@ -0,0 +1,56 @@ +const l_body = document.querySelector('.l_body'); + +// 弹出侧边栏 +function toggleSidebar() { + if (l_body) { + l_body.classList.add('mobile'); + l_body.classList.toggle("sidebar"); + } +} + +function setToc() { + const scrollOffset = 32; + var segs = []; + $("article.md :header").each(function (idx, node) { + segs.push(node) + }); + // 滚动 + $(document, window).scroll(function(e) { + var scrollTop = $(this).scrollTop(); + var topSeg = null + for (var idx in segs) { + var seg = $(segs[idx]) + if (seg.offset().top > scrollTop + scrollOffset) { + continue + } + if (!topSeg) { + topSeg = seg + } else if (seg.offset().top >= topSeg.offset().top) { + topSeg = seg + } + } + if (topSeg) { + $("#toc a.toc-link").removeClass("active") + var link = "#" + topSeg.attr("id") + if (link != '#undefined') { + $('#toc a.toc-link[href="' + encodeURI(link) + '"]').addClass("active") + } else { + $('#toc a.toc-link:first').addClass("active") + } + } + }); +} + +function setSedebar() { + $("#toc a.toc-link").click(function(e) { + l_body.classList.remove("sidebar"); + }); + $(".social-wrap a.comment").click(function(e) { + l_body.classList.remove("sidebar"); + }); +} + +$(function () { + setToc(); + setSedebar(); +}); \ No newline at end of file