hexo-theme-stellar 1.42.1 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude/skills/stellar-theme-dev/SKILL.md +1 -0
  2. package/CHANGELOG.md +31 -0
  3. package/THIRD-PARTY-NOTICES.md +28 -0
  4. package/_config.yml +17 -7
  5. package/_data/icons.yml +10 -9
  6. package/languages/en.yml +11 -0
  7. package/languages/zh-CN.yml +11 -0
  8. package/languages/zh-TW.yml +11 -0
  9. package/layout/_partial/comments/artalk/layout.ejs +1 -1
  10. package/layout/_partial/comments/beaudar/layout.ejs +1 -1
  11. package/layout/_partial/comments/giscus/layout.ejs +1 -1
  12. package/layout/_partial/comments/twikoo/layout.ejs +1 -1
  13. package/layout/_partial/comments/utterances/layout.ejs +1 -1
  14. package/layout/_partial/comments/waline/layout.ejs +1 -1
  15. package/layout/_partial/components/collection-item.ejs +44 -0
  16. package/layout/_partial/components/collection.ejs +26 -0
  17. package/layout/_partial/components/widget-frame.ejs +35 -0
  18. package/layout/_partial/cover/wiki_cover.ejs +82 -26
  19. package/layout/_partial/dropdown.ejs +62 -0
  20. package/layout/_partial/head.ejs +9 -0
  21. package/layout/_partial/main/navbar/breadcrumb/blog.ejs +1 -1
  22. package/layout/_partial/main/post_list/archive_item.ejs +12 -0
  23. package/layout/_partial/main/post_list/topic_card.ejs +21 -9
  24. package/layout/_partial/main/post_list/wiki_card.ejs +49 -10
  25. package/layout/_partial/scripts/defines.ejs +2 -8
  26. package/layout/_partial/scripts/lazyload.ejs +0 -3
  27. package/layout/_partial/scripts.ejs +1 -0
  28. package/layout/_partial/sidebar/index_leftbar.ejs +12 -2
  29. package/layout/_partial/sidebar/logo.ejs +1 -1
  30. package/layout/_partial/sidebar/menu.ejs +21 -23
  31. package/layout/_partial/widgets/components/linklist.ejs +23 -21
  32. package/layout/_partial/widgets/linklist.ejs +7 -12
  33. package/layout/_partial/widgets/recent.ejs +52 -41
  34. package/layout/_partial/widgets/related.ejs +47 -36
  35. package/layout/_partial/widgets/tagtree.ejs +70 -54
  36. package/layout/_partial/widgets/toc.ejs +37 -62
  37. package/layout/_partial/widgets/tree.ejs +38 -51
  38. package/layout/_plugins/mermaid.ejs +3 -4
  39. package/layout/archive.ejs +11 -20
  40. package/layout/collection-preview.ejs +60 -0
  41. package/layout/index_topic.ejs +12 -6
  42. package/layout/index_wiki.ejs +49 -3
  43. package/layout/layout.ejs +4 -3
  44. package/package.json +1 -1
  45. package/scripts/events/index.js +0 -2
  46. package/scripts/generators/stellar-icons.js +1 -1
  47. package/scripts/lib/subtitle.js +5 -1
  48. package/scripts/tags/index.js +1 -0
  49. package/scripts/tags/lib/about.js +1 -1
  50. package/scripts/tags/lib/albums.js +1 -1
  51. package/scripts/tags/lib/banner.js +1 -1
  52. package/scripts/tags/lib/dropdown.js +64 -0
  53. package/scripts/tags/lib/friends.js +1 -1
  54. package/scripts/tags/lib/gallery.js +3 -3
  55. package/scripts/tags/lib/image.js +1 -1
  56. package/scripts/tags/lib/posters.js +1 -1
  57. package/scripts/tags/lib/sites.js +8 -4
  58. package/source/css/_common/base.styl +4 -4
  59. package/source/css/_common/blockquote.styl +2 -2
  60. package/source/css/_common/dropdown.styl +132 -0
  61. package/source/css/_common/html.styl +1 -1
  62. package/source/css/_common/loading.styl +5 -2
  63. package/source/css/_common/title.styl +8 -8
  64. package/source/css/_components/collection.styl +188 -0
  65. package/source/css/_components/layout.styl +1 -1
  66. package/source/css/_components/list.styl +44 -46
  67. package/source/css/_components/md.styl +3 -3
  68. package/source/css/_components/page-transition.styl +22 -0
  69. package/source/css/_components/pages/archives.styl +19 -18
  70. package/source/css/_components/pages/article-indent.styl +2 -2
  71. package/source/css/_components/pages/article-story.styl +9 -5
  72. package/source/css/_components/pages/collection-preview.styl +68 -0
  73. package/source/css/_components/pages/notebook.styl +11 -9
  74. package/source/css/_components/partial/article-footer.styl +7 -4
  75. package/source/css/_components/partial/cover.styl +280 -1
  76. package/source/css/_components/partial/related.styl +10 -6
  77. package/source/css/_components/sidebar/footer.styl +65 -12
  78. package/source/css/_components/sidebar/nav-area.styl +6 -1
  79. package/source/css/_components/sidebar/search.styl +6 -2
  80. package/source/css/_components/tag-plugins/chat.styl +1 -1
  81. package/source/css/_components/tag-plugins/folders.styl +4 -4
  82. package/source/css/_components/tag-plugins/folding.styl +3 -3
  83. package/source/css/_components/tag-plugins/hashtag.styl +2 -3
  84. package/source/css/_components/tag-plugins/mdrender.styl +1 -1
  85. package/source/css/_components/tag-plugins/note.styl +4 -4
  86. package/source/css/_components/tag-plugins/poetry.styl +5 -5
  87. package/source/css/_components/tag-plugins/quot.styl +1 -2
  88. package/source/css/_components/tag-plugins/quote.styl +1 -1
  89. package/source/css/_components/tag-plugins/tabs.styl +2 -2
  90. package/source/css/_components/tag-plugins/timeline.styl +4 -4
  91. package/source/css/_components/widgets/markdown.styl +1 -14
  92. package/source/css/_components/widgets/timeline.styl +2 -2
  93. package/source/css/_components/widgets/toc.styl +22 -20
  94. package/source/css/_components/widgets/widgets.styl +13 -1
  95. package/source/css/_components/wiki-card.styl +209 -0
  96. package/source/css/_custom.styl +22 -20
  97. package/source/css/_plugins/lazyload.styl +8 -5
  98. package/source/css/comments/utterances.styl +2 -2
  99. package/source/css/plugins/mermaid.styl +31 -12
  100. package/source/js/icons.js +1 -1
  101. package/source/js/main.js +62 -6
  102. package/source/js/plugins/adaptive-text.js +46 -2
  103. package/source/js/plugins/dropdown.js +435 -0
  104. package/source/js/plugins/galaxy.js +423 -0
  105. package/source/js/search/algolia-search.js +1 -1
  106. package/source/js/search/local-search.js +1 -1
  107. package/source/js/services/ghinfo.js +31 -3
  108. package/source/js/services/siteinfo.js +26 -0
  109. package/source/js/services/sites.js +6 -2
  110. package/source/js/services.js +5 -2
  111. package/source/js/tagtree.js +7 -7
  112. package/source/js/utils.js +1 -1
  113. package/layout/_partial/widgets/components/link.ejs +0 -21
  114. package/source/css/_components/sidebar/menu.styl +0 -77
  115. package/source/css/_components/widgets/components.styl +0 -68
  116. package/source/css/_components/widgets/list.styl +0 -46
  117. package/source/css/_components/widgets/related.styl +0 -40
@@ -3,63 +3,74 @@ function relatedPostsInTopic() {
3
3
  if (page.topic?.length == 0) {
4
4
  return ''
5
5
  }
6
- const topic = theme.topic.tree[page.topic]
6
+ var topic = theme.topic.tree[page.topic]
7
7
  if (topic == null) {
8
8
  return ''
9
9
  }
10
- var el = ''
11
- el += `<widget class="widget-wrapper related post-list">`
12
- el += `<div class="widget-header dis-select">`
13
- el += `<span class="name">${__('btn.topic') + __('symbol.colon') + (topic.name || topic.title)}</span>`
14
- el += `</div>`
15
- el += `<div class="widget-body">`
16
- for (let post of topic.pages) {
17
- const isActive = post.path == page.path
18
- el += `<a class="item${isActive ? ' active' : ''}" href="${pretty_url(post.path)}">`
19
- el += `<span class="title">${post.title}</span>`
20
- if (isActive) {
21
- el += '<span class="active-dot"></span>'
22
- }
23
- el += `</a>`
10
+ var entries = []
11
+ for (var post of topic.pages) {
12
+ entries.push({
13
+ href: pretty_url(post.path),
14
+ title: post.title,
15
+ active: post.path == page.path
16
+ })
24
17
  }
25
- el += `</div>`
26
- el += `</widget>`
27
- return el
18
+ var body = partial('_partial/components/collection', {options: {
19
+ layout: 'list',
20
+ variant: 'nav',
21
+ density: 'compact',
22
+ items: entries
23
+ }})
24
+ return partial('_partial/components/widget-frame', {
25
+ className: 'related-widget',
26
+ title: __('btn.topic') + __('symbol.colon') + (topic.name || topic.title),
27
+ body: body,
28
+ reveal: false
29
+ })
28
30
  }
31
+
29
32
  function relatedWiki() {
30
- let thisItemObject = theme.wiki.tree[page.wiki]
33
+ var thisItemObject = theme.wiki.tree[page.wiki]
31
34
  if (thisItemObject == null) {
32
35
  return ''
33
36
  }
34
- const relatedItems = thisItemObject.relatedItems || []
37
+ var relatedItems = thisItemObject.relatedItems || []
35
38
  var el = ''
36
- for (let relatedItem of relatedItems) {
37
- el += `<widget class="widget-wrapper${scrollreveal(' ')} post-card">`
38
- el += `<div class="widget-header dis-select">`
39
- el += `<span class="name">${__('meta.more') + __('symbol.colon') + relatedItem.name}</span>`
40
- el += `</div>`
41
- el += `<div class="widget-body">`
42
- for (let id of relatedItem.items) {
43
- // 同一个分组中的其它项目
44
- let item = theme.wiki.tree[id]
45
- el += `<a class="item wiki" href="${pretty_url(item.homepage?.path)}">`
46
- el += `<span class="title">${item.title}</span>`
47
- if (item.description && item.description.length > 0) {
48
- el += `<span class="excerpt">${item.description}</span>`
39
+ for (var relatedItem of relatedItems) {
40
+ var entries = []
41
+ for (var id of relatedItem.items) {
42
+ var relatedProject = theme.wiki.tree[id]
43
+ if (relatedProject) {
44
+ entries.push({
45
+ href: pretty_url(relatedProject.homepage?.path),
46
+ title: relatedProject.title,
47
+ description: relatedProject.description,
48
+ indicator: false
49
+ })
49
50
  }
50
- el += `</a>`
51
51
  }
52
- el += `</div>`
53
- el += `</widget>`
52
+ var body = partial('_partial/components/collection', {options: {
53
+ layout: 'list',
54
+ variant: 'summary',
55
+ density: 'compact',
56
+ items: entries
57
+ }})
58
+ el += partial('_partial/components/widget-frame', {
59
+ className: 'related-summary-widget',
60
+ title: __('meta.more') + __('symbol.colon') + relatedItem.name,
61
+ body: body
62
+ })
54
63
  }
55
64
  return el
56
65
  }
66
+
57
67
  function layoutDiv() {
58
68
  if (page.wiki?.length > 0) {
59
69
  return relatedWiki()
60
70
  } else if (page.topic?.length > 0) {
61
71
  return relatedPostsInTopic()
62
72
  }
73
+ return ''
63
74
  }
64
75
  %>
65
76
  <%- layoutDiv() %>
@@ -1,59 +1,75 @@
1
- <%# 笔记本的标签树 %>
2
- <% const notebook = theme.notebooks.tree[page.notebook] %>
3
- <% const tagTree = notebook?.tagTree %>
4
- <% const isLeaf = tag => tag.id === '' || tag.children.length === 0 %>
5
- <% const getTagcon = tag => {
6
- const tagcons = theme.notebook.tagcons || {}
1
+ <%
2
+ var notebook = theme.notebooks.tree[page.notebook]
3
+ var tagTree = notebook?.tagTree
4
+
5
+ function isLeaf(tag) {
6
+ return tag.id === '' || tag.children.length === 0
7
+ }
8
+
9
+ function getTagcon(tag) {
10
+ var tagcons = theme.notebook.tagcons || {}
7
11
  return tagcons[tag.name] || tagcons[tag.id] || tagcons[tag.part] || tagcons[tag.part.toLowerCase()] || tagcons['']
8
- } %>
12
+ }
9
13
 
10
- <% function layoutTag(tag, level) { %>
11
- <% const active = page.activeTag === tag.id %>
12
- <a class="link<%= active ? ' active' : '' %>" href="<%= pretty_url(tag.path) %>">
13
- <span class="toc-text"<% if (level > 0) { %> style="padding-left: <%= level * 0.875 %>rem;"<% } %>>
14
- <% if (tag.id === '') { %>
15
- <%= __('meta.all_notes') %>
16
- <% } else { %>
17
- <% const tagcon = item.show_tagcon && getTagcon(tag) %>
18
- <% if (tagcon) { %><span class="tagcon"><%- icon(tagcon) %></span><% } %>
19
- <%= tag.part %>
20
- <% } %>
21
- </span>
22
- <span class="toc-text tag-switcher-wrapper">
23
- <span class="tag-switcher" />
24
- </span>
25
- </a>
26
- <% } %>
14
+ function layoutTag(tag, level) {
15
+ var active = page.activeTag === tag.id
16
+ var tagcon = tag.id !== '' && item.show_tagcon ? getTagcon(tag) : ''
17
+ var trailing = ''
18
+ if (!isLeaf(tag)) {
19
+ trailing = '<span class="tag-switcher-wrapper"><span class="tag-switcher"></span></span>'
20
+ }
21
+ return partial('_partial/components/collection-item', {
22
+ item: {
23
+ href: pretty_url(tag.path),
24
+ title: tag.id === '' ? __('meta.all_notes') : tag.part,
25
+ icon: tagcon,
26
+ active: active,
27
+ indicator: false,
28
+ depth: level,
29
+ className: 'tag-tree__link',
30
+ after: trailing
31
+ }
32
+ })
33
+ }
27
34
 
28
- <% function layoutChildTags(tag, level) { %>
29
- <% for (const child of tag.children) { %>
30
- <%= tagAndSub(tagTree.get(child), level + 1) %>
31
- <% } %>
32
- <% } %>
35
+ function tagAndSub(tag, level) {
36
+ if (!tag) {
37
+ return ''
38
+ }
39
+ var active = page.activeTag === tag.id
40
+ var expanded = item.expand_all || (item.expand_active && active) || page.activeTag?.startsWith(tag.id + '/')
41
+ var classes = isLeaf(tag) ? ' is-leaf' : ' is-parent'
42
+ if (expanded) {
43
+ classes += ' is-expanded'
44
+ }
45
+ var el = '<div class="tag-subtree' + classes + '" data-tag="' + escape_html(tag.id) + '">'
46
+ el += layoutTag(tag, level)
47
+ if (!isLeaf(tag)) {
48
+ for (var child of tag.children) {
49
+ el += tagAndSub(tagTree.get(child), level + 1)
50
+ }
51
+ }
52
+ el += '</div>'
53
+ return el
54
+ }
33
55
 
34
- <% function tagAndSub(tag, level) { %>
35
- <% if (!tag) return '' %>
36
- <% const active = page.activeTag === tag.id %>
37
- <% const expanded = item.expand_all || (item.expand_active && active) || page.activeTag?.startsWith(`${tag.id}/`) %>
38
- <% const classes = [isLeaf(tag) ? ' leaf-tag' : ' parent-tag', expanded ? ' expanded' : ''] %>
39
- <div class="tag-subtree<%= classes.join('') %>" data-tag="<%= tag.id %>">
40
- <%= layoutTag(tag, level) %>
41
- <% if (!isLeaf(tag)) { %>
42
- <%= layoutChildTags(tag, level) %>
43
- <% } %>
44
- </div>
45
- <% } %>
56
+ function layoutDiv() {
57
+ if (!tagTree) {
58
+ return ''
59
+ }
60
+ var body = '<div class="ui-collection tag-tree" data-layout="list" data-variant="nav" data-density="compact">'
61
+ body += tagAndSub(tagTree.get(''), 0)
62
+ for (var child of tagTree.get('').children) {
63
+ body += tagAndSub(tagTree.get(child), 0)
64
+ }
65
+ body += '</div>'
66
+ return partial('_partial/components/widget-frame', {
67
+ className: 'tag-tree-widget',
68
+ title: __('meta.tag_tree'),
69
+ body: body,
70
+ attrs: {'data-notebook': page.notebook}
71
+ })
72
+ }
73
+ %>
46
74
 
47
- <% if (tagTree) { %>
48
- <widget class="widget-wrapper<%= scrollreveal(' ') %> post-list" data-notebook="<%= page.notebook %>">
49
- <div class="widget-header dis-select">
50
- <span class="name"><%= __('meta.tag_tree') %></span>
51
- </div>
52
- <div class="widget-body fs14 tag-tree">
53
- <%= tagAndSub(tagTree.get(''), 0) %>
54
- <% for (const child of tagTree.get('').children) { %>
55
- <%= tagAndSub(tagTree.get(child), 0) %>
56
- <% } %>
57
- </div>
58
- </widget>
59
- <% } %>
75
+ <%- layoutDiv() %>
@@ -1,79 +1,54 @@
1
1
  <%
2
-
3
2
  function layoutTocBody() {
4
- if (toc(page.content).length > 0) {
5
- return toc(page.content, {
6
- list_number: item.list_number,
7
- min_depth: item.min_depth,
8
- max_depth: item.max_depth
9
- })
3
+ var tocBody = toc(page.content, {
4
+ list_number: item.list_number,
5
+ min_depth: item.min_depth,
6
+ max_depth: item.max_depth
7
+ })
8
+ if (tocBody.length === 0) {
9
+ return ''
10
10
  }
11
- return ''
11
+ return tocBody.replace('class="toc"', 'class="toc ui-collection-adapter"')
12
12
  }
13
13
 
14
- function layoutTocHeader(title) {
15
- var el = ''
16
- el += `<div class="widget-header dis-select">`
17
- el += `<span class="name">${title || __("meta.toc")}</span>`
18
- el += `<a class="cap-action" onclick="sidebar.toggleTOC()" >${icon('default:rightbar', '', true)}</a>`
19
- el += `</div>`
20
- return el
14
+ function layoutTocAction() {
15
+ return '<a class="cap-action" onclick="sidebar.toggleTOC()">' + icon('default:rightbar', '', true) + '</a>'
21
16
  }
22
17
 
23
- function layoutToc(fallback) {
24
- const tocBody = layoutTocBody()
25
- if (tocBody.length == 0) {
26
- return ''
18
+ function layoutFooter(hasComments) {
19
+ var footer = '<div class="widget-footer">'
20
+ footer += '<a class="top" onclick="util.scrollTop()">'
21
+ footer += icon('default:upup', '', true)
22
+ footer += '<span>' + __('btn.top') + '</span></a>'
23
+ if (hasComments) {
24
+ footer += '<a class="buttom" onclick="util.scrollComment()">'
25
+ footer += icon('default:tocomment', '', true)
26
+ footer += '<span>' + __('btn.comments') + '</span></a>'
27
27
  }
28
- var el = ''
29
- el += `<widget class="widget-wrapper${scrollreveal(' ')} toc" id="data-toc" collapse="${item.collapse}">`
30
- el += layoutTocHeader()
31
- el += `<div class="widget-body">`
32
- el += tocBody
33
- el += `</div>`
34
- el += `</widget>`
35
- return el
28
+ footer += '</div>'
29
+ return footer
36
30
  }
37
31
 
38
- function layoutDiv(fallback) {
39
- const tocBody = layoutTocBody()
40
- const hasToc = tocBody.trim().length > 0
41
- // 远程 md 内容由客户端渲染,构建期正文无标题:
42
- // 预留空 TOC 容器,渲染完成后由 mdrender.js 填充
43
- const hasRemoteMd = has_remote_md(page)
44
- // 页面是否实际渲染评论区,由 _partial/comments/layout.ejs 标记
45
- const hasComments = page.cmt_rendered === true
32
+ function layoutDiv() {
33
+ var tocBody = layoutTocBody()
34
+ var hasToc = tocBody.trim().length > 0
35
+ var hasRemoteMd = has_remote_md(page)
36
+ var hasComments = page.cmt_rendered === true
46
37
  if (!hasToc && !hasRemoteMd && !hasComments) {
47
38
  return ''
48
39
  }
49
- var el = ''
50
- el += `<widget class="widget-wrapper${scrollreveal(' ')} toc" id="data-toc" collapse="${item.collapse}">`
51
- if (hasToc) {
52
- el += layoutTocHeader()
53
- el += `<div class="widget-body">`
54
- el += tocBody
55
- el += `</div>`
56
- } else if (hasRemoteMd) {
57
- el += layoutTocHeader()
58
- el += `<div class="widget-body">`
59
- el += `</div>`
60
- }
61
- el += `<div class="widget-footer">`
62
- el += `<a class="top" onclick="util.scrollTop()">`
63
- el += icon('default:upup', '', true)
64
- el += `<span>${__('btn.top')}</span>`
65
- el += `</a>`
66
- if (hasComments) {
67
- el += `<a class="buttom" onclick="util.scrollComment()">`
68
- el += icon('default:tocomment', '', true)
69
- el += `<span>${__('btn.comments')}</span>`
70
- el += `</a>`
71
- }
72
- el += `</div>`
73
- el += `</widget>`
74
- return el
40
+ return partial('_partial/components/widget-frame', {
41
+ className: 'toc',
42
+ title: hasToc || hasRemoteMd ? __('meta.toc') : '',
43
+ action: hasToc || hasRemoteMd ? layoutTocAction() : '',
44
+ body: hasToc ? tocBody : (hasRemoteMd ? '<nav class="toc ui-collection-adapter"></nav>' : ''),
45
+ footer: layoutFooter(hasComments),
46
+ attrs: {
47
+ id: 'data-toc',
48
+ collapse: item.collapse === 'auto' ? 'auto' : String(item.collapse === true)
49
+ }
50
+ })
75
51
  }
76
-
77
52
  %>
78
53
 
79
54
  <%- layoutDiv() %>
@@ -1,71 +1,58 @@
1
1
  <%
2
- const proj = theme.wiki.tree[page.wiki]
2
+ var proj = theme.wiki.tree[page.wiki]
3
3
 
4
- function layoutTocHeader(title) {
5
- var el = ''
6
- el += `<div class="widget-header dis-select">`
7
- el += `<span class="name">${title || __("meta.toc")}</span>`
8
- el += `</div>`
9
- return el
4
+ function layoutSectionHeader(title) {
5
+ if (!title || title.length === 0) {
6
+ return ''
7
+ }
8
+ return '<div class="widget-header dis-select"><span class="name">' + escape_html(title) + '</span></div>'
10
9
  }
11
10
 
12
11
  function layoutDocTree(pages) {
13
- var el = ''
14
- for (let p of pages) {
15
- if (p.title == null || p.title.length == 0) {
12
+ var entries = []
13
+ for (var docPage of pages) {
14
+ if (docPage.title == null || docPage.title.length === 0 || proj.pages.length <= 1) {
16
15
  continue
17
16
  }
18
- let isActive = ''
19
- if (p.path === page.path) {
20
- isActive += ' active'
21
- }
22
- if (proj.pages.length > 1) {
23
- let href = pretty_url(p.path);
24
- if (p.is_homepage) {
25
- href += '#start'
26
- }
27
- el += `<a class="link${isActive}" href="${href}">`
28
- el += `<span class="toc-text">${p.title}</span>`
29
- if (isActive.length > 0) {
30
- el += '<span class="active-dot"></span>'
31
- }
32
- el += `</a>`
33
- }
17
+ entries.push({
18
+ href: pretty_url(docPage.path),
19
+ title: docPage.title,
20
+ active: docPage.path === page.path,
21
+ gradientRef: 'leftbar-active-icon-grad'
22
+ })
34
23
  }
35
- return el
24
+ return partial('_partial/components/collection', {options: {
25
+ layout: 'list',
26
+ variant: 'nav',
27
+ density: 'compact',
28
+ items: entries
29
+ }})
36
30
  }
37
31
 
38
-
39
- function layoutDiv(fallback) {
40
- if (proj == null) {
41
- return ''
42
- }
43
- if (proj.pages == null || proj.pages.length == 0) {
32
+ function layoutDiv() {
33
+ if (proj == null || proj.pages == null || proj.pages.length === 0 || proj.sections == null || proj.sections.length === 0) {
44
34
  return ''
45
35
  }
46
- if (proj.sections == null || proj.sections.length == 0) {
47
- return ''
48
- }
49
- var el = ''
50
- for (let sec of proj.sections) {
51
- if (sec.pages.length == 0) {
36
+ var body = ''
37
+ for (var section of proj.sections) {
38
+ if (section.pages.length === 0) {
52
39
  continue
53
40
  }
54
- if (sec.title?.length > 0) {
55
- el += layoutTocHeader(sec.title)
56
- }
57
- const docTree = layoutDocTree(sec.pages)
58
- if (docTree.trim().length > 0) {
59
- el += `<div class="widget-body fs14">${docTree}</div>`
41
+ var collection = (layoutDocTree(section.pages) || '').trim()
42
+ if (collection.length > 0) {
43
+ body += '<section class="widget-section">'
44
+ body += layoutSectionHeader(section.title)
45
+ body += collection
46
+ body += '</section>'
60
47
  }
61
48
  }
62
- if (el.trim().length > 0) {
63
- return `<widget class="widget-wrapper doc-tree post-list" data-wiki="${page.wiki}">${el}</widget>`
64
- } else {
65
- return ''
66
- }
49
+ return partial('_partial/components/widget-frame', {
50
+ className: 'doc-tree-widget',
51
+ body: body,
52
+ attrs: {'data-wiki': page.wiki},
53
+ reveal: false
54
+ })
67
55
  }
68
-
69
56
  %>
70
57
 
71
58
  <%- layoutDiv() %>
@@ -3,7 +3,9 @@
3
3
  stellar.initPlugin(() => {
4
4
  const els = document.querySelectorAll('.mermaid');
5
5
  if (els.length > 0) {
6
- utils.css(`<%- url_for('/css/plugins/mermaid.css') %>?v=<%- stellar_info('version') %>`);
6
+ if (<%- conf.style_optimization === true %>) {
7
+ utils.css(`<%- url_for('/css/plugins/mermaid.css') %>?v=<%- stellar_info('version') %>`);
8
+ }
7
9
  const mermaid_config = {
8
10
  startOnLoad: false,
9
11
  theme:
@@ -12,9 +14,6 @@
12
14
  ? "dark"
13
15
  : "<%- conf.theme %>",
14
16
  logLevel: 3,
15
- themeVariables: {
16
- darkMode: true
17
- },
18
17
  flowchart: {
19
18
  useMaxWidth: false,
20
19
  htmlLabels: true,
@@ -24,34 +24,25 @@ function layoutArchiveList() {
24
24
  }
25
25
  el += `<div class="post-list${cls} archives">`
26
26
  var years = []
27
- const posts = page.author != null ? site.posts.filter(p => (p.author || theme.default_author.id) == page.author.id) : site.posts
27
+ var posts = page.author != null ? site.posts.filter(function(post) {
28
+ return (post.author || theme.default_author.id) == page.author.id
29
+ }) : site.posts
28
30
  posts.sort('date', -1).each(function(post) {
29
- post.year = date(post.date, 'YYYY')
30
- if (post.year && (years.includes(post.year) == false) && (post.title || post.date)) {
31
- years.push(post.year)
31
+ post.year = date(post.date, 'YYYY')
32
+ if (post.year && (years.includes(post.year) == false) && (post.title || post.date)) {
33
+ years.push(post.year)
32
34
  }
33
35
  })
34
- for (let year of years) {
36
+ for (var year of years) {
35
37
  el += `<article class="${scrollreveal('')}" id="archive">`
36
- el += `<div class='archive-header h4'>${year}</div>`
38
+ el += `<div class='archive-header h4'>${year}</div>`
37
39
  posts.sort('date', -1).filter(function (post) {
38
40
  post.year = date(post.date, 'YYYY')
39
41
  return post.year == year
40
42
  }).each(function(post) {
41
- el += `<div class="archive-list">`
42
- el +=`<a class='post fs14' href="${pretty_url(post.link || post.path)}">`
43
- el += `<time>${date(post.date, 'MM-DD')}</time>`
44
- el += `<span>`
45
- if (post.title) {
46
- el += post.title
47
- } else if (post.date) {
48
- el += date(post.date, config.date_format)
49
- }
50
- el += `</span>`
51
- el += `</a>`
52
- el += `</div>`
43
+ el += partial('_partial/main/post_list/archive_item', {post: post})
53
44
  })
54
- el += `</article>`
45
+ el += `</article>`
55
46
  }
56
47
  el += `</div>`
57
48
  return el
@@ -65,4 +56,4 @@ function layoutDiv() {
65
56
  }
66
57
  %>
67
58
 
68
- <%- layoutDiv() %>
59
+ <%- layoutDiv() %>
@@ -0,0 +1,60 @@
1
+ <%
2
+ function renderCollection(options) {
3
+ return partial('_partial/components/collection', {options: options})
4
+ }
5
+
6
+ function renderWidget(title, options) {
7
+ return partial('_partial/components/widget-frame', {
8
+ title: title,
9
+ body: renderCollection(options),
10
+ reveal: false
11
+ })
12
+ }
13
+
14
+ function renderSurface(name, surface, width) {
15
+ var navItems = [
16
+ {href: '#active', title: '当前页面', icon: 'default:documents', active: true},
17
+ {href: '#long', title: '这是一个用于检查单行省略和容器适应性的很长标题', icon: 'default:rightbar'},
18
+ {href: '#plain', title: '无图标条目'}
19
+ ]
20
+ var gridItems = [
21
+ {href: '#one', title: '项目一', icon: 'default:documents', active: true},
22
+ {href: '#two', title: '项目二', icon: 'default:rightbar'},
23
+ {href: '#three', title: '项目三', icon: 'default:github'},
24
+ {href: '#four', title: '项目四', icon: 'default:rss'}
25
+ ]
26
+ var summaryItems = [
27
+ {href: '#summary-one', title: '摘要条目', description: '两行说明用于检查文字层级、截断和不同 surface 下的卡片填充。'},
28
+ {href: '#summary-two', title: '第二个摘要条目', description: '正文宽度下仍复用同一 DOM 与状态变量。'}
29
+ ]
30
+ var treeItems = [
31
+ {href: '#root', title: '一级节点', active: true},
32
+ {href: '#child', title: '二级节点', depth: 1, indicator: false},
33
+ {href: '#leaf', title: '三级节点', depth: 2, indicator: false}
34
+ ]
35
+ var html = '<section class="collection-preview__surface" data-ui-surface="' + surface + '" data-preview-width="' + width + '">'
36
+ html += '<header><strong>' + escape_html(name) + '</strong><code>' + escape_html(surface) + ' · ' + width + 'px</code></header>'
37
+ html += renderWidget('紧凑列表', {layout: 'list', variant: 'nav', density: 'compact', items: navItems})
38
+ html += renderWidget('响应式网格', {layout: 'grid', variant: 'nav', columns: 2, items: gridItems})
39
+ html += renderWidget('摘要列表', {layout: 'list', variant: 'summary', items: summaryItems})
40
+ html += renderWidget('层级列表', {layout: 'list', variant: 'nav', density: 'compact', items: treeItems})
41
+ html += '</section>'
42
+ return html
43
+ }
44
+ %>
45
+ <article class="md-text collection-preview">
46
+ <h1>侧边栏集合组件预览</h1>
47
+ <p>此开发页面用于同时检查列表、网格和摘要条目在四种 surface、不同容器宽度及明暗主题下的表现。</p>
48
+ <div class="collection-preview__theme" aria-label="预览主题">
49
+ <span>预览主题</span>
50
+ <button type="button" onclick="document.documentElement.setAttribute('data-theme','light')">Light</button>
51
+ <button type="button" onclick="document.documentElement.setAttribute('data-theme','dark')">Dark</button>
52
+ <button type="button" onclick="document.documentElement.removeAttribute('data-theme')">Auto</button>
53
+ </div>
54
+ <div class="collection-preview__grid">
55
+ <%- renderSurface('左栏 Glass', 'glass', 240) %>
56
+ <%- renderSurface('左栏 Card', 'card', 240) %>
57
+ <%- renderSurface('右侧栏', 'sidebar', 320) %>
58
+ <%- renderSurface('正文区域', 'content', 720) %>
59
+ </div>
60
+ </article>
@@ -1,12 +1,18 @@
1
1
  <%
2
2
  function layout_topic_list(partial) {
3
3
  var el = ''
4
- const { publish_list, tree } = theme.topic
5
- for (let id of publish_list) {
6
- const topic = tree[id]
7
- if (topic == null) {
8
- continue
9
- }
4
+ var publish_list = theme.topic.publish_list
5
+ var tree = theme.topic.tree
6
+ var topics = publish_list.map(function(id) {
7
+ return tree[id]
8
+ }).filter(function(topic) {
9
+ return topic != null
10
+ }).sort(function(a, b) {
11
+ var aDate = a.homepage && a.homepage.date ? new Date(a.homepage.date).getTime() : 0
12
+ var bDate = b.homepage && b.homepage.date ? new Date(b.homepage.date).getTime() : 0
13
+ return bDate - aDate
14
+ })
15
+ for (var topic of topics) {
10
16
  el += `<div class="post-card-wrap${scrollreveal(' ')}">`
11
17
  el += `<div class="post-card topic">`
12
18
  el += partial(topic)