diff --git a/_config.yml b/_config.yml index e2a2e31..28e4872 100755 --- a/_config.yml +++ b/_config.yml @@ -89,7 +89,7 @@ site_tree: post: menu_id: post # 未在 front-matter 中指定 menu_id 时,layout 为 post 的页面默认使用这里配置的 menu_id leftbar: related, ghrepo, ghissues, recent # for pages using 'layout:post' - rightbar: toc + rightbar: ghrepo, toc # 博客专栏文章内页配置 topic: menu_id: post @@ -97,19 +97,19 @@ site_tree: wiki: menu_id: wiki # 未在 front-matter 中指定 menu_id 时,layout 为 wiki 的页面默认使用这里配置的 menu_id leftbar: tree, ghissues, related, recent # for wiki - rightbar: toc + rightbar: ghrepo, toc # 作者信息配置 author: base_dir: author # 只影响自动生成的页面路径 menu_id: post leftbar: recent, timeline - rightbar: + rightbar: timeline # 错误页配置 error_page: menu_id: post '404': '/404.html' leftbar: recent, timeline - rightbar: + rightbar: timeline # 其它自定义页面配置 layout: page page: leftbar: recent diff --git a/_data/icons.yml b/_data/icons.yml index e438561..d14bf93 100644 --- a/_data/icons.yml +++ b/_data/icons.yml @@ -22,10 +22,15 @@ default:bookmark.active: +default:rightbar: + default:pin: default:calendar: default:category: +# 编辑本文 +default:edit: + github:logo: github:repo: github:star: diff --git a/_data/widgets.yml b/_data/widgets.yml index 934117c..f78ca28 100644 --- a/_data/widgets.yml +++ b/_data/widgets.yml @@ -21,24 +21,34 @@ recent: rss: # /atom.xml # npm i hexo-generator-feed limit: 10 # Count of posts +# 页面树(与当前页面强关联的上下篇文章列表) tree: layout: tree -# TOC (valid only in rightbar) +# 本文目录(当前页面内各级标题列表) toc: layout: toc - list_number: true + list_number: false min_depth: 1 max_depth: 6 collapse: false # true / false / auto + # 编辑本文按钮 + edit_this_page: # 从开头开始匹配替换 + '_posts/': https://github.com/xaoxuu/xaoxuu.com/blob/main/source/_posts/ + 'wiki/stellar/': https://github.com/xaoxuu/hexo-theme-stellar-docs/blob/main/ -# github user info +# GitHub 用户信息 ghuser: layout: ghuser - username: github # your github login username + username: # your github login username avatar: true # show avatar or not - menu: true # show menu or not +# 本文作者组件,需要先配置作者信息: authors.yml +author: + layout: author + avatar: true + +# 标签云组件 tagcloud: layout: tagcloud title: 标签云 diff --git a/languages/en.yml b/languages/en.yml index e2bd87c..9fa7fb8 100755 --- a/languages/en.yml +++ b/languages/en.yml @@ -10,11 +10,13 @@ btn: tag: Tag tags: Tags archives: Archives + all_posts: All Posts getting_started: Getting Started + edit: Edit This Page meta: recent_update: Recent Update - toc: TOC + toc: On This Page read_next: READ NEXT prev: Prev next: Next diff --git a/languages/zh-CN.yml b/languages/zh-CN.yml index 9577dc8..b2ce452 100755 --- a/languages/zh-CN.yml +++ b/languages/zh-CN.yml @@ -10,7 +10,9 @@ btn: tag: 标签 tags: 标签 archives: 归档 + all_posts: 所有文章 getting_started: 开始使用 + edit: 编辑本文 meta: recent_update: 最近更新 diff --git a/languages/zh-TW.yml b/languages/zh-TW.yml index f72f34d..5feb558 100755 --- a/languages/zh-TW.yml +++ b/languages/zh-TW.yml @@ -4,13 +4,15 @@ btn: wiki: 文檔 topic: 專欄 recent_publish: 近期發布 - all_wiki: 所有 Wiki + all_wiki: 所有文檔 category: 分類 categories: 分類 tag: 標籤 tags: 標籤 archives: 封存 + all_posts: 所有網誌 getting_started: 開始使用 + edit: 編輯本文 meta: recent_update: 最近更新 diff --git a/layout/_partial/main/navbar/article_top_area.ejs b/layout/_partial/main/navbar/article_top_area.ejs index 58ff1ae..4f6e830 100644 --- a/layout/_partial/main/navbar/article_top_area.ejs +++ b/layout/_partial/main/navbar/article_top_area.ejs @@ -25,8 +25,6 @@ function layoutDiv() { el += partial('dateinfo') // end 2.left el += `` - // 2.right - el += partial('ghinfo') // end 1.main el += `` return el diff --git a/layout/_partial/menubtn.ejs b/layout/_partial/menubtn.ejs index e5c393c..84e2146 100644 --- a/layout/_partial/menubtn.ejs +++ b/layout/_partial/menubtn.ejs @@ -1,5 +1,8 @@ - diff --git a/layout/_partial/plugins/comments/waline/script.ejs b/layout/_partial/plugins/comments/waline/script.ejs index aed62b8..03267db 100644 --- a/layout/_partial/plugins/comments/waline/script.ejs +++ b/layout/_partial/plugins/comments/waline/script.ejs @@ -32,7 +32,6 @@ }); } window.addEventListener('DOMContentLoaded', (event) => { - console.log('DOM fully loaded and parsed'); load_comment(); }); diff --git a/layout/_partial/widgets/author.ejs b/layout/_partial/widgets/author.ejs new file mode 100644 index 0000000..8a43c87 --- /dev/null +++ b/layout/_partial/widgets/author.ejs @@ -0,0 +1,37 @@ +<% + +var author = null +if (theme.authors) { + if (page.author?.length > 0 && theme.authors[page.author] != null) { + author = theme.authors[page.author] + } else { + author = theme.default_author + } +} + +function layoutDiv() { + if (author == null) { + return '' + } + var el = '' + el += `` + // body + el += `
` + if (item.avatar) { + el += `
` + } + // username + el += `

${author.name}

` + el += `

${author.desc || author.description}

` + + // homepage + el += `` + el += `
` + el += `
` + return el +} +%> +<%- layoutDiv() %> diff --git a/layout/_partial/widgets/components/edit.ejs b/layout/_partial/widgets/components/edit.ejs new file mode 100644 index 0000000..29dc76d --- /dev/null +++ b/layout/_partial/widgets/components/edit.ejs @@ -0,0 +1,24 @@ +<% +function parseURL() { + const source = page.source || '' + var url + for (let id of Object.keys(map)) { + if (source.startsWith(id)) { + return source.replace(id, map[id]) + } + } +} +function layoutDiv() { + const url = parseURL() + if (url == null) { + return '' + } + var el = '' + el += `` + el += icon('default:edit') + el += `${__('btn.edit')}` + el += `` + return el +} +%> +<%- layoutDiv() %> diff --git a/layout/_partial/widgets/ghuser.ejs b/layout/_partial/widgets/ghuser.ejs index 88e11b9..d4c1dac 100644 --- a/layout/_partial/widgets/ghuser.ejs +++ b/layout/_partial/widgets/ghuser.ejs @@ -22,7 +22,7 @@ function layoutDiv() { return el; } - el += `` + el += `` // body el += '
'; if (item.avatar) { diff --git a/layout/_partial/widgets/related.ejs b/layout/_partial/widgets/related.ejs index 3e344a3..17cf2c1 100644 --- a/layout/_partial/widgets/related.ejs +++ b/layout/_partial/widgets/related.ejs @@ -31,7 +31,7 @@ function relatedWiki() { if (thisItemObject == null) { return '' } - const relatedItems = thisItemObject.relatedItems + const relatedItems = thisItemObject.relatedItems || [] var el = '' for (let relatedItem of relatedItems) { el += `` diff --git a/layout/_partial/widgets/toc.ejs b/layout/_partial/widgets/toc.ejs index 5914a23..8a102db 100644 --- a/layout/_partial/widgets/toc.ejs +++ b/layout/_partial/widgets/toc.ejs @@ -15,11 +15,12 @@ function layoutTocHeader(title) { var el = '' el += `
` el += `${title || __("meta.toc")}` + el += `${icon('default:rightbar')}` el += `
` return el } -function layoutDiv(fallback) { +function layoutToc(fallback) { const tocBody = layoutTocBody() if (tocBody.length == 0) { return '' @@ -34,6 +35,29 @@ function layoutDiv(fallback) { return el } +function layoutDiv(fallback) { + const editBtn = partial('components/edit', {map: item.edit_this_page}) + const tocBody = layoutTocBody() + if (tocBody.length == 0 && editBtn.length == 0) { + return '' + } + var el = '' + el += `` + if (tocBody.length > 0) { + el += layoutTocHeader() + el += `
` + el += tocBody + el += `
` + } + if (editBtn.trim().length > 0) { + el += `` + } + el += `
` + return el +} + %> <%- layoutDiv() %> diff --git a/layout/layout.ejs b/layout/layout.ejs index 137aee2..387ce4c 100755 --- a/layout/layout.ejs +++ b/layout/layout.ejs @@ -52,12 +52,12 @@ html += `` html += partial('_partial/sidebar/logo', {where: 'main'}) html += body html += partial('_partial/main/footer') - html += partial('_partial/menubtn') - html += `
` + html += `
` html += `
` html += `` + html += partial('_partial/menubtn') html += `` html += `
` html += partial('_partial/scripts/index') diff --git a/source/css/_common/device.styl b/source/css/_common/device.styl index 0987cc1..78e363b 100644 --- a/source/css/_common/device.styl +++ b/source/css/_common/device.styl @@ -9,12 +9,15 @@ .float-panel position: sticky + grid-column-end: span 3 right: 0 bottom: 2rem float: right z-index: 10 display: flex - border-radius: 2rem + flex-direction: column + border-radius: 0.5rem + margin-left: auto margin-right: 1rem overflow: hidden --blur-px: 16px @@ -27,7 +30,7 @@ --blur-bg: alpha(#000, .4) // 侧边栏弹出按钮 -.leftbar-toggle.mobile +.float-panel button cursor: pointer color: var(--text) background: none @@ -41,8 +44,16 @@ trans1 transform width: auto height: 28px + // 侧边栏弹出后 -.l_body.mobile.leftbar .leftbar-toggle.mobile +.l_body[leftbar] .float-panel, .l_body[rightbar] .float-panel + box-shadow: 0 0 4px -2px $color-theme, 0 0 24px -12px $color-theme +.l_body[leftbar] .float-panel button + background: var(--card) + +.l_body[leftbar] .float-panel button.leftbar-toggle + color: $color-theme + border-color: var(--block-border) svg g fill: currentColor fill-opacity: 0.3 @@ -50,8 +61,15 @@ transform: translateX(2px) -.l_body.mobile.leftbar - .leftbar-toggle.mobile - background: var(--card) - color: $color-hover - border-color: var(--block-border) +.l_body[rightbar] .float-panel button + background: var(--card) + +.l_body[rightbar] .float-panel button.rightbar-toggle + color: $color-theme + border-color: var(--block-border) + svg g + fill: currentColor + fill-opacity: 0.3 + path#sep + transform: translateX(2px) + diff --git a/source/css/_custom.styl b/source/css/_custom.styl index 55c375e..2c658ac 100644 --- a/source/css/_custom.styl +++ b/source/css/_custom.styl @@ -67,30 +67,32 @@ $border-button = 4px // 可以动态变化的属性 :root - --width-left: 288px + --width-sidebar: 288px --width-main: 720px --fsp: $fs-body --fsh2: 'calc(%s + 11px)' % var(--fsp) --fsh3: 'calc(%s + 7px)' % var(--fsp) --fsh4: 'calc(%s + 4px)' % var(--fsp) - --gap-l: 16px + --gap-margin: 16px + --gap-padding: 16px + --gap-max: calc(var(--gap-margin) + var(--gap-padding)) + --gap-p: 'calc(%s + 4px)' % $fs-body // gap for paragraph --gap-p-compact: 'calc(%s * 0.75)' % $fs-body // desktop 2k or larger @media screen and (min-width: $device-2k) - --gap-l: 32px - --width-left: 352px + --width-sidebar: 352px --width-main: 780px // desktop 4k or larger @media screen and (min-width: $device-4k) --width-main: 860px // iPad 竖屏 @media screen and (max-width: $device-tablet) - --width-left: 252px + --width-sidebar: 252px // iPad 竖屏 @media screen and (max-width: $device-mobile-max) - --width-left: 288px + --width-sidebar: 288px // 文章布局风格 .l_body.story diff --git a/source/css/_layout/layout.styl b/source/css/_layout/layout.styl index 8bba77e..c2b0b63 100644 --- a/source/css/_layout/layout.styl +++ b/source/css/_layout/layout.styl @@ -1,13 +1,13 @@ .l_body display: grid grid-template-columns: 1fr minmax(200px,var(--width-main)) 1fr - grid-gap: var(--gap-l) + grid-gap: var(--gap-margin) margin: auto font-size: var(--fsp) .l_body aside z-index: 8 - width: var(--width-left) + width: var(--width-sidebar) flex-shrink: 0 position: sticky position: -webkit-sticky @@ -19,6 +19,29 @@ height: 100% overflow visible +// 平板布局 +@media screen and (max-width: $device-laptop) + .laptop-only + display: block !important + .l_body + .l_right + position: fixed + height: calc(100% - 8px * 2) + transform: translateX(320px) + transition: transform .38s ease-out + margin: 0 + right: 8px + box-shadow: $boxshadow-card-float + z-index: 10 + background: var(--site-bg) + overflow: scroll + .l_body[rightbar] + .l_right + transform: translateX(0px) + .main-mask + opacity 1 + pointer-events: inherit + // 手机布局 @media screen and (max-width: $device-mobile-max) .mobile-only @@ -29,16 +52,14 @@ .l_left position: fixed transform: translateX(-320px) + transition: transform .38s ease-out margin: 0 left: 8px box-shadow: $boxshadow-card-float z-index: 10 .l_main max-width: 100% - .l_body.mobile - .l_left - transition: transform .38s ease-out - .l_body.mobile.leftbar + .l_body[leftbar] .l_left transform: translateX(0px) .main-mask diff --git a/source/css/_layout/main.styl b/source/css/_layout/main.styl index bbfd035..882423a 100644 --- a/source/css/_layout/main.styl +++ b/source/css/_layout/main.styl @@ -1,6 +1,6 @@ .l_main position: relative - padding-bottom: "calc(1 * %s)" % var(--gap-l) + padding-bottom: var(--gap-max) @media screen and (min-width: $device-mobile-max) padding-top: 8px header diff --git a/source/css/_layout/sidebar/footer.styl b/source/css/_layout/sidebar/footer.styl index b664f47..0dcd848 100644 --- a/source/css/_layout/sidebar/footer.styl +++ b/source/css/_layout/sidebar/footer.styl @@ -1,5 +1,5 @@ .l_left footer.footer - margin: 0.5rem var(--gap-l) 1rem + margin: 0.5rem var(--gap-max) 1rem .social-wrap display: grid diff --git a/source/css/_layout/sidebar/nav-area.styl b/source/css/_layout/sidebar/nav-area.styl index 8d3f222..96bbae8 100644 --- a/source/css/_layout/sidebar/nav-area.styl +++ b/source/css/_layout/sidebar/nav-area.styl @@ -1,2 +1,2 @@ .nav-area - margin: 32px var(--gap-l) 0 \ No newline at end of file + margin: 32px var(--gap-margin) 0 \ No newline at end of file diff --git a/source/css/_layout/sidebar/sidebar.styl b/source/css/_layout/sidebar/sidebar.styl index 8e4d377..bcae093 100644 --- a/source/css/_layout/sidebar/sidebar.styl +++ b/source/css/_layout/sidebar/sidebar.styl @@ -4,15 +4,25 @@ border-radius: $border-card-l overflow: hidden .header - margin: var(--gap-l) var(--gap-l) 0 - margin-top: "calc(2 * %s)" % var(--gap-l) + margin: var(--gap-max) var(--gap-margin) 0 @media screen and (min-width: 1400px) margin-left: auto - margin-right: "calc(2 * %s)" % var(--gap-l) + margin-right: var(--gap-max) @media screen and (min-width: $device-mobile-max) >.widgets:first-child>.widget-wrapper:first-child - margin-top: "calc(2 * %s)" % var(--gap-l) - + margin-top: "calc(2 * %s)" % var(--gap-max) + +.l_right + margin: 0 8px 0 0 + border-radius: $border-card-l +@media screen and (min-width: 1400px) + .l_left + margin-left: auto + margin-right: var(--gap-max) + .l_right + margin-left: var(--gap-margin) + margin-right: auto + .l_left background-size: cover if hexo-config('style.leftbar') && hexo-config('style.leftbar.background-image') diff --git a/source/css/_layout/tag-plugins/banner.styl b/source/css/_layout/tag-plugins/banner.styl index 7fc0627..5d6c98e 100644 --- a/source/css/_layout/tag-plugins/banner.styl +++ b/source/css/_layout/tag-plugins/banner.styl @@ -129,8 +129,8 @@ @media screen and (min-width: $device-mobile-max) .banner.author.top - margin-left: var(--gap-l) - margin-right: var(--gap-l) + margin-left: var(--gap-max) + margin-right: var(--gap-max) @media screen and (max-width: $device-mobile-max) .banner.top diff --git a/source/css/_layout/widgets/ghrepo.styl b/source/css/_layout/widgets/ghrepo.styl index 0e3e5fb..fcf513c 100644 --- a/source/css/_layout/widgets/ghrepo.styl +++ b/source/css/_layout/widgets/ghrepo.styl @@ -5,7 +5,7 @@ color: var(--text-p2) background: var(--card) border-radius: $border-card - box-shadow: $boxshadow-card + hoverable-card() >div+div margin-top: 0.5rem span diff --git a/source/css/_layout/widgets/ghuser.styl b/source/css/_layout/widgets/ghuser.styl index db68b28..1dc861b 100644 --- a/source/css/_layout/widgets/ghuser.styl +++ b/source/css/_layout/widgets/ghuser.styl @@ -1,21 +1,21 @@ -.widget-wrapper.ghuser +.widget-wrapper.user-card .widget-header+.widget-body margin: 0.75rem 0 -.widget-wrapper.ghuser .widget-body +.widget-wrapper.user-card .widget-body text-align: center background: var(--card) border-radius: $border-card padding: 1rem - box-shadow: $boxshadow-card + hoverable-card() -.widgets .widget-wrapper.ghuser +.widgets .widget-wrapper.user-card .avatar display: block border-radius: 100% margin: 1rem auto 1.25rem auto - max-width: 75% + max-width: 128px overflow: hidden - img + img display: block @media screen and (max-width: $device-tablet) max-width: 50% @@ -32,6 +32,7 @@ .follow font-weight: 500 border-radius: 64px + margin: 1rem 0 0 padding: 0.5rem 1rem background: $color-theme color: var(--card) @@ -45,6 +46,8 @@ trans1: background svg margin-right: 6px + height: 1.5em + width: auto &:hover background: $color-hover diff --git a/source/css/_layout/widgets/timeline.styl b/source/css/_layout/widgets/timeline.styl index f95e7e8..e3c944f 100644 --- a/source/css/_layout/widgets/timeline.styl +++ b/source/css/_layout/widgets/timeline.styl @@ -1,4 +1,4 @@ -.widget-wrapper.timeline +.widget-wrapper.timeline .widget-body margin-top: 0.5rem .body @@ -12,7 +12,7 @@ border-bottom: 1px solid $color-hover .tag-plugin.timeline .timenode .header - margin: 0.5rem 16px + margin: 0.5rem var(--gap-padding) txt-ellipsis() .user-info background: var(--alpha50) @@ -27,8 +27,6 @@ color: var(--text-p2) .body border-radius: $border-card - background: var(--alpha50) - box-shadow: none p,li --fsp: $fsp3 code @@ -40,4 +38,9 @@ .tag-plugin.timeline[api] .body .footer - background: none \ No newline at end of file + background: none + + +.l_left .widget-wrapper.timeline .body + box-shadow: none + background: var(--alpha50) diff --git a/source/css/_layout/widgets/toc.styl b/source/css/_layout/widgets/toc.styl index 5a352d7..afce445 100644 --- a/source/css/_layout/widgets/toc.styl +++ b/source/css/_layout/widgets/toc.styl @@ -1,3 +1,6 @@ +.widget-wrapper.toc + background: var(--site-bg) + z-index 1 // 目录基本样式 .widget-wrapper.toc .toc --fsp: $fsp2 @@ -11,7 +14,7 @@ margin: 2px 0 list-style: none a - padding: 4px var(--gap-l) + padding: 4px var(--gap-max) color: var(--text-p2) display: block overflow: hidden @@ -20,7 +23,7 @@ position relative &:before,&:after position: absolute - left: 4px + left: 'calc(%s * 0.5)' % var(--gap-max) width: 8px height: 8px top: 'calc(%s - 4px)' % 50% @@ -39,12 +42,19 @@ opacity 0 // 固定位置 -.l_right .widget-wrapper.toc +.l_right .widgets .widget-wrapper.toc position: sticky position: -webkit-sticky - top: 32px - max-height: 'calc(90vh - 2 * %s)' % @top - overflow: scroll + top: 0 + margin-top: 0 + padding: 16px 0 + .widget-body .toc + max-height: 75vh + @media screen and (max-width: $device-laptop) + max-height: unset + overflow: scroll + + // 各级缩进样式 .widget-wrapper.toc .toc @@ -87,4 +97,48 @@ .widget-wrapper.toc[collapse='true'] ol:has(> .toc-item a.active) display: block .widget-wrapper.toc[collapse='auto'] ol:has(> .toc-item a.active) - display: block \ No newline at end of file + display: block + +// 手动折叠 +.widget-wrapper.toc + .widget-body + display: grid + grid-template-rows: 1fr + trans1 all + overflow hidden +.l_right .widgets .widget-wrapper.toc .widget-header .cap-action:hover + background: var(--block-border) +.l_right .widgets .widget-wrapper.toc.collapse + .widget-header .cap-action + background: var(--block-border) + .widget-body + grid-template-rows: 0fr + +// 编辑本文按钮 +.widget-wrapper.toc .widget-footer + margin-top: 8px + color: var(--text-p2) + position relative + padding-top: 8px + &:before + content: '' + position absolute + background: var(--block-border) + top: 0 + height: 1px + left: var(--gap-max) + right: var(--gap-max) + a + display: flex + align-items: center + color: inherit + font-size: $fs-14 + padding: 8px 16px + margin: 0 calc(var(--gap-max) - 16px) + border-radius: 4px + svg,img + height: 16px + width: auto + margin-right: 8px + a:hover + background: var(--block-hover) \ No newline at end of file diff --git a/source/css/_layout/widgets/widgets.styl b/source/css/_layout/widgets/widgets.styl index f854341..9e862eb 100644 --- a/source/css/_layout/widgets/widgets.styl +++ b/source/css/_layout/widgets/widgets.styl @@ -10,11 +10,10 @@ scrollbar(0, 0) z-index: 1 line-height: 1.2 - margin: 0 var(--gap-l) .widget-wrapper .widget-header - padding-left: var(--gap-l) - padding-right: var(--gap-l) + padding-left: var(--gap-padding) + padding-right: var(--gap-padding) display: flex justify-content: space-between align-items: baseline @@ -50,16 +49,33 @@ fill: $color-hover .widget-body - margin: 0.5rem 0 color: var(--text-p1) p margin-top: .5em margin-bottom: .5em line-height: 1.5 - .widget-header+.widget-body - margin-top: 0 .widget-wrapper display: block - margin: 32px 0 \ No newline at end of file + +.l_left .widgets + margin: 0 var(--gap-margin) + .widget-wrapper + margin: 32px 0 + +.l_right .widgets + .widget-wrapper + margin-top: 8px + .widget-header + padding-left: var(--gap-max) + padding-right: var(--gap-max) + &:not(.toc) + margin-left: var(--gap-margin) + margin-right: var(--gap-margin) + .widget-wrapper+.widget-wrapper + margin-top: 32px + @media screen and (max-width: $device-laptop) + .widget-wrapper + margin-top: var(--gap-margin) + border-radius: $border-card diff --git a/source/js/main.js b/source/js/main.js index cfb316f..28ba760 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -1,4 +1,3 @@ -console.log('\n' + '%c Stellar v' + stellar.version + ' %c\n' + stellar.github + '\n', 'color:#e8fafe;background:#03c7fa;padding:8px;border-radius:4px', 'margin-top:8px'); // utils const util = { @@ -76,12 +75,27 @@ const hud = { const l_body = document.querySelector('.l_body'); -const leftbar = { - toggle: () => { +const sidebar = { + leftbar: () => { if (l_body) { - l_body.classList.add('mobile'); - l_body.classList.toggle("leftbar"); + l_body.toggleAttribute('leftbar'); + l_body.removeAttribute('rightbar'); } + }, + rightbar: () => { + if (l_body) { + l_body.toggleAttribute('rightbar'); + l_body.removeAttribute('leftbar'); + } + }, + dismiss: () => { + if (l_body) { + l_body.removeAttribute('leftbar'); + l_body.removeAttribute('rightbar'); + } + }, + toggleTOC: () => { + document.querySelector('#data-toc').classList.toggle('collapse'); } } @@ -91,53 +105,58 @@ const init = { const scrollOffset = 32; var segs = []; $("article.md-text :header").each(function (idx, node) { - segs.push(node) + segs.push(node); }); - // 定位到激活的目录树(不如pjax体验好) - // const widgets = document.querySelector('.widgets') - // const e1 = document.querySelector('.doc-tree-link.active') - // const offsetTop = e1.getBoundingClientRect().top - widgets.getBoundingClientRect().top - 100 - // if (offsetTop > 0) { - // widgets.scrollBy({top: offsetTop, behavior: 'smooth'}) - // } - // 滚动 - $(document, window).scroll(function (e) { + function activeTOC() { var scrollTop = $(this).scrollTop(); - var topSeg = null + var topSeg = null; for (var idx in segs) { - var seg = $(segs[idx]) + var seg = $(segs[idx]); if (seg.offset().top > scrollTop + scrollOffset) { - continue + continue; } if (!topSeg) { - topSeg = seg + topSeg = seg; } else if (seg.offset().top >= topSeg.offset().top) { - topSeg = seg + topSeg = seg; } } if (topSeg) { - $("#data-toc a.toc-link").removeClass("active") - var link = "#" + topSeg.attr("id") + $("#data-toc a.toc-link").removeClass("active"); + var link = "#" + topSeg.attr("id"); if (link != '#undefined') { - const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]') + const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]'); if (highlightItem.length > 0) { - highlightItem.addClass("active") - const e0 = document.querySelector('#data-toc') - console.log('e0', e0); - const e1 = document.querySelector('#data-toc a.toc-link[href="' + encodeURI(link) + '"]') - const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 200 - const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64 - if (offsetTop < 0) { - e0.scrollBy(0, offsetTop) - } else if (offsetBottom > 0) { - e0.scrollBy(0, offsetBottom) - } + highlightItem.addClass("active"); } } else { - $('#data-toc a.toc-link:first').addClass("active") + $('#data-toc a.toc-link:first').addClass("active"); } } - }) + } + function scrollTOC() { + const e0 = document.querySelector('#data-toc .toc'); + const e1 = document.querySelector('#data-toc .toc a.toc-link.active'); + if (e0 == null || e1 == null) { + return; + } + const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100; + const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64; + if (offsetTop < 0) { + e0.scrollBy({top: offsetTop, behavior: "smooth"}); + } else if (offsetBottom > 0) { + e0.scrollBy({top: offsetBottom, behavior: "smooth"}); + } + } + + var timeout = null; + window.addEventListener('scroll', function() { + activeTOC(); + if(timeout !== null) clearTimeout(timeout); + timeout = setTimeout(function() { + scrollTOC(); + }.bind(this), 300); + }); }) }, leftbar: () => {