diff --git a/_config.yml b/_config.yml index 4f3e53c..e2a2e31 100755 --- a/_config.yml +++ b/_config.yml @@ -62,12 +62,14 @@ site_tree: # -- 列表类页面 -- # # 主页配置 home: - leftbar: welcome, recent, timeline + leftbar: welcome, recent + rightbar: timeline # 博客列表页配置 index_blog: base_dir: blog # 只影响自动生成的页面路径 menu_id: post # 未在 front-matter 中指定 menu_id 时,layout 为 post 的页面默认使用这里配置的 menu_id - leftbar: welcome, recent, timeline # for categories/tags/archives + leftbar: welcome, recent # for categories/tags/archives + rightbar: timeline nav_tabs: # 近期发布 分类 标签 专栏 归档 and ... # '朋友文章': /friends/rss/ # 博客专栏列表页配置 @@ -78,34 +80,40 @@ site_tree: index_wiki: base_dir: wiki # 只影响自动生成的页面路径 menu_id: wiki # 未在 front-matter 中指定 menu_id 时,layout 为 wiki 的页面默认使用这里配置的 menu_id - leftbar: toc, ghissues, related, recent # for wiki + leftbar: ghissues, related, recent # for wiki + rightbar: timeline nav_tabs: # 'more': https://github.com/xaoxuu # -- 内容类页面 -- # # 博客文章内页配置 post: menu_id: post # 未在 front-matter 中指定 menu_id 时,layout 为 post 的页面默认使用这里配置的 menu_id - leftbar: toc, related, ghrepo, ghissues, recent # for pages using 'layout:post' + leftbar: related, ghrepo, ghissues, recent # for pages using 'layout:post' + rightbar: toc # 博客专栏文章内页配置 topic: menu_id: post # 文档内页配置 wiki: menu_id: wiki # 未在 front-matter 中指定 menu_id 时,layout 为 wiki 的页面默认使用这里配置的 menu_id - leftbar: toc, ghissues, related, recent # for wiki + leftbar: tree, ghissues, related, recent # for wiki + rightbar: toc # 作者信息配置 author: base_dir: author # 只影响自动生成的页面路径 menu_id: post leftbar: recent, timeline + rightbar: # 错误页配置 error_page: menu_id: post '404': '/404.html' leftbar: recent, timeline + rightbar: # 其它自定义页面配置 layout: page page: - leftbar: toc, recent, timeline + leftbar: recent + rightbar: toc, timeline diff --git a/_data/widgets.yml b/_data/widgets.yml index 20448b9..934117c 100644 --- a/_data/widgets.yml +++ b/_data/widgets.yml @@ -21,13 +21,15 @@ recent: rss: # /atom.xml # npm i hexo-generator-feed limit: 10 # Count of posts -# TOC (valid only in layout:post/wiki) +tree: + layout: tree + +# TOC (valid only in rightbar) toc: layout: toc - list_number: false - min_depth: 2 - max_depth: 5 - fallback: # recent # Use a backup widget when toc does not exist. + list_number: true + min_depth: 1 + max_depth: 6 collapse: false # true / false / auto # github user info diff --git a/layout/_partial/menubtn.ejs b/layout/_partial/menubtn.ejs index fc71874..e5c393c 100644 --- a/layout/_partial/menubtn.ejs +++ b/layout/_partial/menubtn.ejs @@ -1,5 +1,5 @@ diff --git a/layout/_partial/sidebar/index.ejs b/layout/_partial/sidebar/index_leftbar.ejs similarity index 99% rename from layout/_partial/sidebar/index.ejs rename to layout/_partial/sidebar/index_leftbar.ejs index 56ca751..d40142d 100755 --- a/layout/_partial/sidebar/index.ejs +++ b/layout/_partial/sidebar/index_leftbar.ejs @@ -47,6 +47,8 @@ if (page.leftbar == null) { if (typeof page.leftbar == 'string') { page.leftbar = page.leftbar.replace(/ /g, '').split(','); } + + function layoutTitle(main, url, sub) { var el = ''; el += ''; diff --git a/layout/_partial/sidebar/index_rightbar.ejs b/layout/_partial/sidebar/index_rightbar.ejs new file mode 100644 index 0000000..b94436e --- /dev/null +++ b/layout/_partial/sidebar/index_rightbar.ejs @@ -0,0 +1,79 @@ +<% + +const wiki = theme.wiki.tree[page.wiki] +const topic = theme.topic.tree[page.topic] + +if (page.rightbar == null) { + const { site_tree } = theme + var sidebar + if (is_home()) { + sidebar = site_tree.home.rightbar + } else if (is_category() || is_tag() || is_archive() || ['categories', 'tags', 'archives'].includes(page.layout)) { + sidebar = site_tree.index_blog.rightbar + } else if (page.layout === 'index_topic') { + // 专栏列表页等同于博客列表页 + sidebar = site_tree.index_blog.rightbar + } else if (page.topic?.length > 0) { + // 专栏文章内页等同于普通文章内页 + sidebar = site_tree.post.rightbar + } else if (page.layout === 'index_wiki') { + sidebar = site_tree.index_wiki.rightbar + } else if (page.wiki?.length > 0) { + sidebar = site_tree.wiki.rightbar + } else if (page.layout === '404') { + sidebar = site_tree.error_page.rightbar + } else if (page.layout === 'page') { + sidebar = site_tree.page.rightbar + } else if (page.layout === 'post') { + sidebar = site_tree.post.rightbar + } else if (page.layout == null) { + sidebar = site_tree.page.rightbar + } else { + sidebar = [] + } + + if (topic?.rightbar) { + sidebar = topic.rightbar + } + if (wiki?.rightbar) { + sidebar = wiki.rightbar + } + + page.rightbar = sidebar +} + + +// parse array string +if (typeof page.rightbar == 'string') { + page.rightbar = page.rightbar.replace(/ /g, '').split(','); +} + +function layoutWidgets() { + var el = ''; + el += '
'; + if (page.rightbar) { + page.rightbar.forEach((w, i) => { + let name = '' + let widget = {} + if (typeof w == 'string') { + name = w + } else if (typeof w == 'object' && w.override) { + name = w.override + } + if (name in theme.widgets) { + Object.assign(widget, theme.widgets[name]) + } + if (typeof w == 'object' && (w.override || w.layout)) { + Object.assign(widget, w) + } + if (widget && widget.layout) { + el += partial('../widgets/' + widget.layout, {item: widget}) + } + }); + } + el += '
'; + return el; +} + +%> +<%- layoutWidgets() %> \ No newline at end of file diff --git a/layout/_partial/widgets/toc.ejs b/layout/_partial/widgets/toc.ejs index b72068a..5914a23 100644 --- a/layout/_partial/widgets/toc.ejs +++ b/layout/_partial/widgets/toc.ejs @@ -1,16 +1,13 @@ <% -const proj = theme.wiki.tree[page.wiki] -var hasTOC = true + function layoutTocBody() { if (toc(page.content).length > 0) { - hasTOC = true return toc(page.content, { list_number: item.list_number, min_depth: item.min_depth, max_depth: item.max_depth - }); + }) } - hasTOC = false return '' } @@ -22,94 +19,18 @@ function layoutTocHeader(title) { return el } -function layoutDocTree(pages) { - var el = '' - for (let p of pages) { - if (p.title == null || p.title.length == 0) { - continue - } - let isActive = '' - if (p.path === page.path) { - isActive += ' active' - } - el += `
` - if (proj.pages.length > 1) { - let href = url_for(p.path); - if (p.is_homepage) { - href += '#start' - } - el += `` - el += `${p.title}` - if (isActive.length > 0) { - el += icon('default:bookmark.active') - } - el += `` - } - if (p.path === page.path) { - el += layoutTocBody() - } - el += `
` - } - return el -} - - function layoutDiv(fallback) { - var type = '' - if (proj?.pages) { - type = proj.pages.length > 1 ? 'multi' : 'single' - } else { - let toc_content = toc(page.content) - if (toc_content && toc_content.length > 0) { - type = 'single' - } + const tocBody = layoutTocBody() + if (tocBody.length == 0) { + return '' } - var el = '' - if (type.length > 0) { - el += `` - if (proj) { - // wiki 布局 - if (proj.sections && proj.sections.length > 0 && proj.pages.length > 1) { // 多 pages - for (let sec of proj.sections) { - if (sec.pages.length == 0) { - continue - } - if (sec.title?.length > 0) { - el += layoutTocHeader(sec.title) - } - el += `
` - el += layoutDocTree(sec.pages) - el += `
` - } - } else { // 单 page - if (proj.pages.length == 1) { - el += layoutTocHeader() - } - el += `
` - el += layoutDocTree(proj.pages) - el += `
` - if (hasTOC == false) { - return '' - } - } - } else { - // post 布局 - el += layoutTocHeader() - el += `
` - el += `
` - el += layoutTocBody() - el += `
` - el += `
` - if (hasTOC == false) { - return '' - } - } - el += `
` - } else if (item.fallback) { - const fallback = theme.widgets[item.fallback] - el += partial(fallback.layout, {item: fallback}) - } + el += `` + el += layoutTocHeader() + el += `
` + el += tocBody + el += `
` + el += `
` return el } diff --git a/layout/_partial/widgets/tree.ejs b/layout/_partial/widgets/tree.ejs new file mode 100644 index 0000000..897d4fd --- /dev/null +++ b/layout/_partial/widgets/tree.ejs @@ -0,0 +1,68 @@ +<% +const proj = theme.wiki.tree[page.wiki] + +function layoutTocHeader(title) { + var el = '' + el += `
` + el += `${title || __("meta.toc")}` + el += `
` + return el +} + +function layoutDocTree(pages) { + var el = '' + for (let p of pages) { + if (p.title == null || p.title.length == 0) { + continue + } + let isActive = '' + if (p.path === page.path) { + isActive += ' active' + } + if (proj.pages.length > 1) { + let href = url_for(p.path); + if (p.is_homepage) { + href += '#start' + } + el += `` + el += `${p.title}` + if (isActive.length > 0) { + el += icon('default:bookmark.active') + } + el += `` + } + } + return el +} + + +function layoutDiv(fallback) { + if (proj == null) { + return '' + } + if (proj.pages == null || proj.pages.length == 0) { + return '' + } + if (proj.sections == null || proj.sections.length == 0) { + return '' + } + var el = '' + el += `` + for (let sec of proj.sections) { + if (sec.pages.length == 0) { + continue + } + if (sec.title?.length > 0) { + el += layoutTocHeader(sec.title) + } + el += `
` + el += layoutDocTree(sec.pages) + el += `
` + } + el += `
` + return el +} + +%> + +<%- layoutDiv() %> diff --git a/layout/layout.ejs b/layout/layout.ejs index 2d5c7a7..137aee2 100755 --- a/layout/layout.ejs +++ b/layout/layout.ejs @@ -45,7 +45,7 @@ html += `` html += `
` html += `` html += `
` @@ -55,6 +55,9 @@ html += `` html += partial('_partial/menubtn') html += `
` html += `
` + html += `` html += `
` html += `
` html += partial('_partial/scripts/index') diff --git a/source/css/_layout/layout.styl b/source/css/_layout/layout.styl index cc7baa5..8bba77e 100644 --- a/source/css/_layout/layout.styl +++ b/source/css/_layout/layout.styl @@ -5,7 +5,7 @@ margin: auto font-size: var(--fsp) -.l_body .l_left +.l_body aside z-index: 8 width: var(--width-left) flex-shrink: 0 @@ -13,6 +13,12 @@ position: -webkit-sticky top: 8px +.l_body .l_right + height: 100% + .widgets + height: 100% + overflow visible + // 手机布局 @media screen and (max-width: $device-mobile-max) .mobile-only diff --git a/source/css/_layout/widgets/list.styl b/source/css/_layout/widgets/list.styl index 3e81d69..583c4cd 100644 --- a/source/css/_layout/widgets/list.styl +++ b/source/css/_layout/widgets/list.styl @@ -25,4 +25,7 @@ height: 1em width: auto transform: scale(1.2) - \ No newline at end of file + +.widget-wrapper.post-list + .widget-body+.widget-header + margin-top: 28px \ No newline at end of file diff --git a/source/css/_layout/widgets/toc.styl b/source/css/_layout/widgets/toc.styl new file mode 100644 index 0000000..5a352d7 --- /dev/null +++ b/source/css/_layout/widgets/toc.styl @@ -0,0 +1,90 @@ +// 目录基本样式 +.widget-wrapper.toc .toc + --fsp: $fsp2 + padding: 0 + margin: 0 + position relative + list-style: none + .toc-child + padding-left: 1em + li + margin: 2px 0 + list-style: none + a + padding: 4px var(--gap-l) + color: var(--text-p2) + display: block + overflow: hidden + text-overflow: ellipsis + white-space: nowrap + position relative + &:before,&:after + position: absolute + left: 4px + width: 8px + height: 8px + top: 'calc(%s - 4px)' % 50% + border-radius: 8px + background: var(--block) + background: $color-theme + &:after + opacity 0 + animation: wave 1s linear infinite + @keyframes wave + from + transform: scale(1) + opacity 1 + to + transform: scale(2) + opacity 0 + +// 固定位置 +.l_right .widget-wrapper.toc + position: sticky + position: -webkit-sticky + top: 32px + max-height: 'calc(90vh - 2 * %s)' % @top + overflow: scroll + +// 各级缩进样式 +.widget-wrapper.toc .toc + .toc-item + font-weight: 500 + --fsp: $fsp1 + .toc-item .toc-item + font-weight: 400 + --fsp: $fsp2 + +// 高亮样式 +.widget-wrapper.toc .toc a.toc-link.active + color: var(--text-p0) + &:before,&:after + content: '' + +.widget-wrapper.toc .toc a.toc-link:hover + color: $color-theme + +// 始终折叠 +.widget-wrapper.toc[collapse='true'] + .toc-item a.toc-link+ol + display: none + // 激活上级目录时显示子目录 + .toc a.toc-link.active+ol + display: block + +// 自动折叠 +.widget-wrapper.toc[collapse='auto'] + .toc-item a.toc-link+ol + display: none + // 激活上级目录时显示子目录 + .toc a.toc-link.active+ol + display: block + // 鼠标放上去时显示子目录 + &:hover a.toc-link+ol + display: block + +// 子目录激活时显示 +.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 diff --git a/source/css/_layout/widgets/toc_blog.styl b/source/css/_layout/widgets/toc_blog.styl deleted file mode 100644 index b37746e..0000000 --- a/source/css/_layout/widgets/toc_blog.styl +++ /dev/null @@ -1,3 +0,0 @@ -.widget-wrapper.toc.single .doc-tree - &.active>.toc - border-left: 2px solid var(--alpha50) diff --git a/source/css/_layout/widgets/toc_common.styl b/source/css/_layout/widgets/toc_common.styl deleted file mode 100644 index 63ef803..0000000 --- a/source/css/_layout/widgets/toc_common.styl +++ /dev/null @@ -1,92 +0,0 @@ - -.toc-item - margin-top: 2px -.toc-child - margin-top: 2px -.widget-wrapper.toc .widget-body - margin-top: 0 - ul ul, ul ol - padding-left: 0 - ol ul, ol ol - padding-left: 0 - - .toc - padding: 0 - margin: 0 - padding-left: 0.25rem - .toc-item .toc-link - padding: 0.5rem - font-weight: 500 - font-size: $fs-13 - color: var(--text-p1) - .toc-child .toc-item .toc-link - padding: 0.25rem 0.5rem 0.25rem 1.3rem - font-weight: 400 - color: var(--text-p2) - .toc-child .toc-child .toc-item .toc-link - padding-left: 2.1rem - font-size: $fs-12 - color: var(--text-p3) - .toc-child .toc-child .toc-child .toc-item .toc-link - padding-left: 2.9rem - - -.widget-wrapper.toc .toc-item - color: var(--text-p2) - font-size: $fs-12 - padding: 0 - list-style: none - &.active - background: var(--alpha50) - border-left-color: @color - .toc-child .toc-item - padding: 0 -.widget-wrapper.toc a.toc-link - color: inherit - display: block - line-height: 1.2 - border-radius: $border-bar - position: relative - trans1 background - &:before - content: '' - position: absolute - left: -6px - top: 'calc(50% - %s)' % 6px - bottom: 'calc(50% - %s)' % 6px - width: 2px - border-radius: 2px - background: var(--text) - visibility: hidden - &.active - background: var(--alpha50) - &:before - visibility: visible - &:hover - background: var(--alpha100) - - -// 始终折叠 -.widget-wrapper.toc[collapse='true'] - .toc-item a.toc-link+ol - display: none - // 激活上级目录时显示子目录 - .toc a.toc-link.active+ol - display: block - -// 自动折叠 -.widget-wrapper.toc[collapse='auto'] - .toc-item a.toc-link+ol - display: none - // 激活上级目录时显示子目录 - .toc a.toc-link.active+ol - display: block - // 鼠标放上去时显示子目录 - &:hover a.toc-link+ol - display: block - -// 子目录激活时显示 -.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 diff --git a/source/css/_layout/widgets/toc_wiki.styl b/source/css/_layout/widgets/toc_wiki.styl deleted file mode 100644 index d813e7e..0000000 --- a/source/css/_layout/widgets/toc_wiki.styl +++ /dev/null @@ -1,62 +0,0 @@ -.doc-tree+.doc-tree - margin-top: 2px - -.widget-wrapper.toc.multi - // .widget-header - // color: $color-theme - // filter: brightness(75%) - .widget-body+.widget-header - margin-top: 28px - -// 其它分页链接 -.widget-wrapper.toc.multi .doc-tree - border-radius: $border-bar - overflow: hidden - a.doc-tree-link - color: var(--text-p1) - padding: 0 16px - display: flex - min-height: 32px - justify-content: space-between - align-items: center - font-size: $fs-14 - position: relative - trans1 background - .toc-text - txt-ellipsis() - svg,img - flex-shrink: 0 - width: 1em - height: 1em - transform: scale(1.2) - &:after - position: absolute - right: .5rem - &:only-child - &.active - background: var(--alpha50) - &:hover - background: var(--alpha100) - &:hover - background: var(--alpha100) - - -// 当前分页链接 -.widget-wrapper.toc.multi .doc-tree.active - a.doc-tree-link - background: var(--alpha100) - font-weight: 500 - &:hover:after - content: none - >.toc - padding: 4px 10px - border: 1px solid var(--alpha50) - background: var(--alpha20) - border-bottom-left-radius: $border-bar - border-bottom-right-radius: $border-bar - a.toc-link:before - left: -7px - width: 4px - background: var(--text-p2) - a.toc-link:hover - background: var(--alpha100) diff --git a/source/css/_layout/widgets/tree.styl b/source/css/_layout/widgets/tree.styl new file mode 100644 index 0000000..e69de29 diff --git a/source/js/main.js b/source/js/main.js index a603d9a..cfb316f 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -122,7 +122,8 @@ const init = { const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]') if (highlightItem.length > 0) { highlightItem.addClass("active") - const e0 = document.querySelector('.widgets') + 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