hexo-theme-stellar 1.44.0 → 2.0.0-rc.2

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 (377) hide show
  1. package/CHANGELOG.md +63 -5
  2. package/CONTRIBUTING.md +29 -120
  3. package/README.md +66 -73
  4. package/README_EN.md +66 -73
  5. package/_config.yml +890 -743
  6. package/_data/icons.yml +43 -171
  7. package/_data/widgets.yml +1 -1
  8. package/assets/icon-v2-x512.webp +0 -0
  9. package/languages/en.yml +59 -2
  10. package/languages/zh-CN.yml +59 -2
  11. package/languages/zh-TW.yml +59 -2
  12. package/layout/404.ejs +7 -4
  13. package/layout/_partial/comments/artalk/layout.ejs +3 -2
  14. package/layout/_partial/comments/beaudar/layout.ejs +2 -2
  15. package/layout/_partial/comments/giscus/layout.ejs +2 -5
  16. package/layout/_partial/comments/layout.ejs +11 -40
  17. package/layout/_partial/comments/twikoo/layout.ejs +3 -2
  18. package/layout/_partial/comments/utterances/layout.ejs +2 -2
  19. package/layout/_partial/comments/waline/layout.ejs +3 -2
  20. package/layout/_partial/components/collection-item.ejs +30 -13
  21. package/layout/_partial/components/collection.ejs +2 -2
  22. package/layout/_partial/cover/index.ejs +5 -2
  23. package/layout/_partial/cover/wiki_cover.ejs +39 -28
  24. package/layout/_partial/dropdown.ejs +26 -14
  25. package/layout/_partial/head.ejs +96 -69
  26. package/layout/_partial/main/article/contributors.ejs +12 -9
  27. package/layout/_partial/main/article/post_footer.ejs +47 -0
  28. package/layout/_partial/main/article/post_read_next.ejs +22 -0
  29. package/layout/_partial/main/article/post_related.ejs +14 -0
  30. package/layout/_partial/main/article/post_tags.ejs +12 -0
  31. package/layout/_partial/main/article/share.ejs +55 -0
  32. package/layout/_partial/main/footer.ejs +11 -10
  33. package/layout/_partial/main/{navbar/nav_tabs_blog.ejs → listing_nav/blog.ejs} +21 -18
  34. package/layout/_partial/main/listing_nav/wiki.ejs +56 -0
  35. package/layout/_partial/main/navbar/article_banner.ejs +39 -35
  36. package/layout/_partial/main/navbar/breadcrumb/blog.ejs +15 -28
  37. package/layout/_partial/main/navbar/breadcrumb/note.ejs +12 -5
  38. package/layout/_partial/main/navbar/breadcrumb/wiki.ejs +15 -11
  39. package/layout/_partial/main/navbar/dateinfo.ejs +28 -12
  40. package/layout/_partial/main/navbar/ghinfo.ejs +5 -3
  41. package/layout/_partial/main/notebook/note_card.ejs +12 -17
  42. package/layout/_partial/main/notebook/note_tags.ejs +3 -4
  43. package/layout/_partial/main/notebook/notebook_card.ejs +11 -4
  44. package/layout/_partial/main/pin_slider.ejs +48 -43
  45. package/layout/_partial/main/post_list/archive_item.ejs +8 -4
  46. package/layout/_partial/main/post_list/latest_post_card.ejs +10 -4
  47. package/layout/_partial/main/post_list/post_card.ejs +39 -90
  48. package/layout/_partial/main/post_list/topic_card.ejs +7 -5
  49. package/layout/_partial/main/post_list/wiki_card.ejs +16 -13
  50. package/layout/_partial/menubtn.ejs +3 -3
  51. package/layout/_partial/primitives/item.ejs +8 -0
  52. package/layout/_partial/primitives/navigation.ejs +17 -0
  53. package/layout/_partial/primitives/region.ejs +16 -0
  54. package/layout/_partial/primitives/section.ejs +8 -0
  55. package/layout/_partial/primitives/shell.ejs +35 -0
  56. package/layout/_partial/regions/widgets.ejs +84 -0
  57. package/layout/_partial/scripts/defines.ejs +46 -76
  58. package/layout/_partial/scripts/runtime.ejs +55 -0
  59. package/layout/_partial/scripts.ejs +18 -42
  60. package/layout/_partial/search/dialog.ejs +33 -0
  61. package/layout/_partial/search/shortcut.ejs +1 -0
  62. package/layout/_partial/sidebar/brand.ejs +127 -0
  63. package/layout/_partial/sidebar/menu.ejs +59 -14
  64. package/layout/_partial/sidebar/search.ejs +58 -41
  65. package/layout/_partial/widgets/actions.ejs +25 -0
  66. package/layout/_partial/widgets/author.ejs +9 -5
  67. package/layout/_partial/widgets/components/linklist.ejs +1 -2
  68. package/layout/_partial/widgets/ghissues.ejs +7 -10
  69. package/layout/_partial/widgets/ghrepo.ejs +23 -16
  70. package/layout/_partial/widgets/ghuser.ejs +3 -3
  71. package/layout/_partial/widgets/recent.ejs +25 -21
  72. package/layout/_partial/widgets/related.ejs +25 -34
  73. package/layout/_partial/widgets/settings.ejs +17 -0
  74. package/layout/_partial/widgets/tagtree.ejs +18 -10
  75. package/layout/_partial/widgets/toc.ejs +17 -9
  76. package/layout/_partial/widgets/tree.ejs +12 -13
  77. package/layout/archive.ejs +20 -13
  78. package/layout/categories.ejs +4 -3
  79. package/layout/collection-preview.ejs +8 -9
  80. package/layout/index.ejs +32 -43
  81. package/layout/index_topic.ejs +6 -13
  82. package/layout/index_wiki.ejs +17 -34
  83. package/layout/layout.ejs +195 -65
  84. package/layout/notebooks.ejs +3 -3
  85. package/layout/notes.ejs +4 -4
  86. package/layout/page.ejs +95 -50
  87. package/layout/settings.ejs +109 -0
  88. package/layout/tags.ejs +4 -3
  89. package/{THIRD-PARTY-NOTICES.md → legal/THIRD-PARTY-NOTICES.md} +8 -4
  90. package/package.json +28 -6
  91. package/scripts/commands/stellar.js +55 -0
  92. package/scripts/events/index.js +15 -9
  93. package/scripts/events/lib/authors.js +9 -7
  94. package/scripts/events/lib/config-hot-reload.js +65 -0
  95. package/scripts/events/lib/config-schema.js +20 -0
  96. package/scripts/events/lib/config.js +22 -63
  97. package/scripts/events/lib/content-config.js +5 -0
  98. package/scripts/events/lib/doc_tree.js +99 -9
  99. package/scripts/events/lib/links.js +6 -3
  100. package/scripts/events/lib/notebooks.js +200 -8
  101. package/scripts/events/lib/utils.js +4 -4
  102. package/scripts/events/lib/version-check.js +57 -3
  103. package/scripts/filters/index.js +2 -27
  104. package/scripts/filters/lib/img_lazyload.js +4 -126
  105. package/scripts/filters/lib/img_onerror.js +14 -17
  106. package/scripts/filters/lib/page-view-model.js +152 -0
  107. package/scripts/generators/404.js +13 -8
  108. package/scripts/generators/author.js +16 -11
  109. package/scripts/generators/notebooks.js +68 -39
  110. package/scripts/generators/search.js +62 -67
  111. package/scripts/generators/settings.js +43 -0
  112. package/scripts/generators/stellar-icons.js +13 -5
  113. package/scripts/generators/topic.js +24 -13
  114. package/scripts/generators/wiki.js +49 -21
  115. package/scripts/helpers/ai_label.js +6 -12
  116. package/scripts/helpers/brand.js +17 -0
  117. package/scripts/helpers/browser_runtime_manifest.js +12 -0
  118. package/scripts/helpers/caption.js +8 -0
  119. package/scripts/helpers/category_color.js +13 -13
  120. package/scripts/helpers/collection.js +18 -0
  121. package/scripts/helpers/comments_model.js +14 -0
  122. package/scripts/helpers/extension_assets.js +8 -0
  123. package/scripts/helpers/json_ld.js +16 -7
  124. package/scripts/helpers/mdrender.js +3 -9
  125. package/scripts/helpers/menu.js +9 -0
  126. package/scripts/helpers/post_view_model.js +23 -0
  127. package/scripts/helpers/regions.js +37 -0
  128. package/scripts/helpers/scrollreveal.js +7 -7
  129. package/scripts/helpers/search_domain.js +34 -0
  130. package/scripts/helpers/service_provider.js +9 -0
  131. package/scripts/helpers/settings.js +16 -0
  132. package/scripts/helpers/share_action.js +8 -0
  133. package/scripts/helpers/stellar_config.js +12 -0
  134. package/scripts/helpers/stellar_data.js +8 -0
  135. package/scripts/helpers/stellar_info.js +21 -16
  136. package/scripts/helpers/stellar_inject.js +9 -0
  137. package/scripts/helpers/ui_classes.js +12 -0
  138. package/scripts/lib/ai_label.js +14 -11
  139. package/scripts/lib/brand.js +41 -0
  140. package/scripts/lib/browser-runtime.js +115 -0
  141. package/scripts/lib/caption.js +21 -0
  142. package/scripts/lib/collection-pipeline/adapters/notebook.js +62 -0
  143. package/scripts/lib/collection-pipeline/adapters/post.js +20 -0
  144. package/scripts/lib/collection-pipeline/adapters/topic.js +82 -0
  145. package/scripts/lib/collection-pipeline/adapters/wiki.js +20 -0
  146. package/scripts/lib/collection-pipeline/index.js +169 -0
  147. package/scripts/lib/collection-pipeline/registry.js +27 -0
  148. package/scripts/lib/collection-pipeline/shared.js +164 -0
  149. package/scripts/lib/comments.js +60 -0
  150. package/scripts/lib/config-inject.js +20 -0
  151. package/scripts/lib/config-schema.js +1095 -0
  152. package/scripts/lib/content-config.js +157 -0
  153. package/scripts/lib/content-defaults.js +56 -0
  154. package/scripts/lib/content-membership.js +233 -0
  155. package/scripts/lib/contribution-contract.js +165 -0
  156. package/scripts/lib/contribution-registry.js +429 -0
  157. package/scripts/lib/doc_tree.js +46 -44
  158. package/scripts/lib/doctor.js +296 -0
  159. package/scripts/lib/front-matter.js +29 -0
  160. package/scripts/lib/hero-effect-registry.js +262 -0
  161. package/scripts/lib/html-images.js +128 -0
  162. package/scripts/lib/internal-constants.js +152 -0
  163. package/scripts/lib/layout-config.js +62 -0
  164. package/scripts/lib/mdrender_html.js +36 -23
  165. package/scripts/lib/menu.js +36 -0
  166. package/scripts/lib/model-schema.js +90 -0
  167. package/scripts/lib/models/index.js +1542 -0
  168. package/scripts/lib/new-note.js +172 -0
  169. package/scripts/lib/page-view-model-registry.js +103 -0
  170. package/scripts/lib/regions.js +132 -0
  171. package/scripts/lib/runtime-data.js +23 -0
  172. package/scripts/lib/safe-path.js +44 -0
  173. package/scripts/lib/search-domain.js +59 -0
  174. package/scripts/lib/seo.js +10 -10
  175. package/scripts/lib/service-provider.js +12 -0
  176. package/scripts/lib/settings.js +16 -0
  177. package/scripts/lib/share-services.js +96 -0
  178. package/scripts/lib/source-config.js +27 -0
  179. package/scripts/lib/theme-metadata.js +22 -0
  180. package/scripts/lib/ui-capabilities.js +32 -0
  181. package/scripts/lib/widget-registry.js +150 -0
  182. package/scripts/lib/wiki_readme.js +15 -11
  183. package/scripts/schema/config-rules.js +290 -0
  184. package/scripts/schema/config-schema.js +163 -0
  185. package/scripts/schema/content-config-rules.js +264 -0
  186. package/scripts/schema/content-config-schema.js +321 -0
  187. package/scripts/schema/model-schema.js +971 -0
  188. package/scripts/schema/schema-utils.js +48 -0
  189. package/scripts/tags/index.js +2 -3
  190. package/scripts/tags/lib/albums.js +6 -6
  191. package/scripts/tags/lib/banner.js +10 -4
  192. package/scripts/tags/lib/box.js +1 -1
  193. package/scripts/tags/lib/button.js +1 -1
  194. package/scripts/tags/lib/chat.js +9 -31
  195. package/scripts/tags/lib/checkbox.js +6 -1
  196. package/scripts/tags/lib/copy.js +4 -1
  197. package/scripts/tags/lib/dropdown.js +6 -4
  198. package/scripts/tags/lib/emoji.js +5 -10
  199. package/scripts/tags/lib/friends.js +4 -4
  200. package/scripts/tags/lib/gallery.js +7 -7
  201. package/scripts/tags/lib/ghcard.js +5 -3
  202. package/scripts/tags/lib/gist.js +16 -0
  203. package/scripts/tags/lib/grid.js +4 -2
  204. package/scripts/tags/lib/hashtag.js +1 -1
  205. package/scripts/tags/lib/icon.js +1 -1
  206. package/scripts/tags/lib/image.js +1 -1
  207. package/scripts/tags/lib/link.js +6 -3
  208. package/scripts/tags/lib/mark.js +8 -3
  209. package/scripts/tags/lib/md.js +1 -1
  210. package/scripts/tags/lib/note.js +1 -1
  211. package/scripts/tags/lib/okr.js +18 -1
  212. package/scripts/tags/lib/posters.js +6 -6
  213. package/scripts/tags/lib/quot.js +15 -5
  214. package/scripts/tags/lib/rating.js +7 -4
  215. package/scripts/tags/lib/sites.js +8 -6
  216. package/scripts/tags/lib/tip.js +6 -6
  217. package/scripts/tags/lib/toc.js +2 -2
  218. package/scripts/tags/lib/vote.js +8 -5
  219. package/source/css/_appearances/_mixins.styl +258 -0
  220. package/source/css/_appearances/card.styl +30 -0
  221. package/source/css/_appearances/flat.styl +44 -0
  222. package/source/css/_appearances/glass.styl +138 -0
  223. package/source/css/_appearances/minimal.styl +325 -0
  224. package/source/css/_common/base.styl +5 -9
  225. package/source/css/_common/blockquote.styl +0 -1
  226. package/source/css/_common/button.styl +1 -1
  227. package/source/css/_common/device.styl +24 -42
  228. package/source/css/_common/dropdown.styl +20 -14
  229. package/source/css/_common/highlight.styl +5 -12
  230. package/source/css/_common/icon.styl +38 -0
  231. package/source/css/_common/input.styl +33 -0
  232. package/source/css/_common/loading.styl +2 -2
  233. package/source/css/_common/svg.styl +0 -8
  234. package/source/css/_components/collection.styl +21 -64
  235. package/source/css/_components/layout.styl +524 -84
  236. package/source/css/_components/list.styl +36 -22
  237. package/source/css/_components/main.styl +16 -19
  238. package/source/css/_components/md.styl +8 -13
  239. package/source/css/_components/pages/article-indent.styl +1 -1
  240. package/source/css/_components/pages/article-story.styl +7 -6
  241. package/source/css/_components/pages/article-tech.styl +5 -5
  242. package/source/css/_components/pages/collection-preview.styl +1 -5
  243. package/source/css/_components/pages/settings.styl +184 -0
  244. package/source/css/_components/partial/article-banner.styl +2 -2
  245. package/source/css/_components/partial/article-footer.styl +0 -32
  246. package/source/css/_components/partial/article-share.styl +48 -0
  247. package/source/css/_components/partial/article-tags.styl +1 -1
  248. package/source/css/_components/partial/cover.styl +13 -13
  249. package/source/css/_components/partial/listing-nav.styl +68 -0
  250. package/source/css/_components/partial/paginator.styl +1 -1
  251. package/source/css/_components/pin-slider.styl +3 -3
  252. package/source/css/_components/sidebar/brand.styl +135 -0
  253. package/source/css/_components/sidebar/footer.styl +14 -31
  254. package/source/css/_components/sidebar/nav-area.styl +4 -0
  255. package/source/css/_components/sidebar/search.styl +176 -26
  256. package/source/css/_components/sidebar/sidebar.styl +76 -110
  257. package/source/css/_components/tag-plugins/banner.styl +16 -28
  258. package/source/css/_components/tag-plugins/checkbox.styl +7 -22
  259. package/source/css/_components/tag-plugins/copy.styl +3 -5
  260. package/source/css/_components/tag-plugins/gallery.styl +2 -2
  261. package/source/css/_components/tag-plugins/grid.styl +3 -0
  262. package/source/css/_components/tag-plugins/image.styl +2 -1
  263. package/source/css/_components/tag-plugins/link.styl +0 -1
  264. package/source/css/_components/tag-plugins/mark.styl +19 -4
  265. package/source/css/_components/tag-plugins/mdrender.styl +2 -2
  266. package/source/css/_components/tag-plugins/navbar.styl +23 -17
  267. package/source/css/_components/tag-plugins/note.styl +2 -2
  268. package/source/css/_components/tag-plugins/okr.styl +1 -2
  269. package/source/css/_components/tag-plugins/quot.styl +5 -0
  270. package/source/css/_components/tag-plugins/rating.styl +3 -2
  271. package/source/css/_components/tag-plugins/timeline.styl +1 -1
  272. package/source/css/_components/tag-plugins/tip.styl +1 -1
  273. package/source/css/_components/tag-plugins/vote.styl +3 -2
  274. package/source/css/_components/widgets/ghrepo.styl +2 -1
  275. package/source/css/_components/widgets/ghuser.styl +4 -6
  276. package/source/css/_components/widgets/settings.styl +49 -0
  277. package/source/css/_components/widgets/timeline.styl +2 -2
  278. package/source/css/_components/widgets/toc.styl +12 -33
  279. package/source/css/_components/widgets/widgets.styl +14 -19
  280. package/source/css/_components/wiki-card.styl +2 -2
  281. package/source/css/_custom.styl +26 -32
  282. package/source/css/_defines/func.styl +47 -37
  283. package/source/css/_defines/theme_base.styl +8 -10
  284. package/source/css/_plugins/card-hover.styl +1 -1
  285. package/source/css/_plugins/copycode.styl +16 -19
  286. package/source/css/_plugins/index.styl +3 -8
  287. package/source/css/_plugins/lazyload.styl +1 -1
  288. package/source/css/main.styl +12 -0
  289. package/source/js/main.js +302 -59
  290. package/source/js/plugins/adaptive-text.js +33 -16
  291. package/source/js/plugins/card-hover.js +2 -24
  292. package/source/js/plugins/copycode.js +10 -16
  293. package/source/js/plugins/voice.js +51 -48
  294. package/source/js/profile.js +316 -0
  295. package/source/js/runtime/asset-loader.js +61 -0
  296. package/source/js/runtime/extension-registry.js +149 -0
  297. package/source/js/runtime/extensions/card-hover.js +5 -0
  298. package/source/js/runtime/extensions/color-scheme-switch.js +101 -0
  299. package/source/js/runtime/extensions/comments.js +200 -0
  300. package/source/js/runtime/extensions/deferred-icons.js +53 -0
  301. package/source/js/{plugins → runtime/extensions}/dropdown.js +69 -30
  302. package/source/js/runtime/extensions/feature.js +200 -0
  303. package/source/js/runtime/extensions/hero-effect.js +179 -0
  304. package/source/js/runtime/extensions/reveal.js +80 -0
  305. package/source/js/runtime/extensions/search.js +23 -0
  306. package/source/js/{services.js → runtime/extensions/services.js} +67 -54
  307. package/source/js/runtime/extensions/settings.js +235 -0
  308. package/source/js/runtime/hero-effects/ferrofluid.js +385 -0
  309. package/source/js/{plugins → runtime/hero-effects}/galaxy.js +53 -177
  310. package/source/js/runtime/hero-effects/light-rays.js +293 -0
  311. package/source/js/runtime/index.js +75 -0
  312. package/source/js/runtime/legacy-request-adapter.js +47 -0
  313. package/source/js/runtime/request-cache.js +219 -0
  314. package/source/js/search/algolia-search.js +76 -51
  315. package/source/js/search/highlight.js +1 -1
  316. package/source/js/search/local-search.js +96 -57
  317. package/source/js/search/shortcut.js +31 -20
  318. package/source/js/services/friends_and_posts.js +6 -1
  319. package/source/js/services/rating.js +14 -6
  320. package/source/js/services/siteinfo.js +3 -7
  321. package/source/js/services/timeline.js +1 -1
  322. package/source/js/services/vote.js +7 -5
  323. package/source/js/services/weibo.js +1 -1
  324. package/source/js/utils.js +19 -444
  325. package/.claude/skills/stellar-theme-dev/SKILL.md +0 -51
  326. package/_data/chat_users.yml +0 -0
  327. package/layout/_partial/comments/artalk/script.ejs +0 -76
  328. package/layout/_partial/comments/beaudar/script.ejs +0 -33
  329. package/layout/_partial/comments/giscus/script.ejs +0 -31
  330. package/layout/_partial/comments/script.ejs +0 -3
  331. package/layout/_partial/comments/twikoo/script.ejs +0 -25
  332. package/layout/_partial/comments/utterances/script.ejs +0 -33
  333. package/layout/_partial/comments/waline/script.ejs +0 -43
  334. package/layout/_partial/main/article/article_footer.ejs +0 -164
  335. package/layout/_partial/main/article/article_tags.ejs +0 -16
  336. package/layout/_partial/main/article/read_next.ejs +0 -63
  337. package/layout/_partial/main/article/related_posts.ejs +0 -16
  338. package/layout/_partial/main/navbar/nav_tabs_wiki.ejs +0 -52
  339. package/layout/_partial/scripts/bootstrap.ejs +0 -37
  340. package/layout/_partial/scripts/lazyload.ejs +0 -89
  341. package/layout/_partial/sidebar/grad-def.ejs +0 -26
  342. package/layout/_partial/sidebar/index_leftbar.ejs +0 -191
  343. package/layout/_partial/sidebar/index_rightbar.ejs +0 -94
  344. package/layout/_partial/sidebar/logo.ejs +0 -99
  345. package/layout/_plugins/adaptive_text.ejs +0 -11
  346. package/layout/_plugins/card_hover.ejs +0 -32
  347. package/layout/_plugins/copycode.ejs +0 -17
  348. package/layout/_plugins/fancybox.ejs +0 -53
  349. package/layout/_plugins/heti.ejs +0 -21
  350. package/layout/_plugins/index.ejs +0 -50
  351. package/layout/_plugins/mathjax.ejs +0 -49
  352. package/layout/_plugins/mermaid.ejs +0 -33
  353. package/layout/_plugins/preload.ejs +0 -9
  354. package/layout/_plugins/scrollreveal.ejs +0 -102
  355. package/layout/_plugins/search/algolia_search.ejs +0 -12
  356. package/layout/_plugins/search/local_search.ejs +0 -9
  357. package/layout/_plugins/swiper.ejs +0 -27
  358. package/layout/_plugins/tianli_gpt.ejs +0 -14
  359. package/scripts/commands/new-note.js +0 -49
  360. package/scripts/events/lib/merge_posts.js +0 -48
  361. package/scripts/events/lib/topic_tree.js +0 -48
  362. package/scripts/helpers/related_posts.js +0 -51
  363. package/scripts/helpers/subtitle.js +0 -8
  364. package/scripts/lib/notebooks.js +0 -181
  365. package/scripts/lib/subtitle.js +0 -28
  366. package/scripts/tags/lib/about.js +0 -48
  367. package/source/css/_components/page-transition.styl +0 -22
  368. package/source/css/_components/partial/navbar.styl +0 -51
  369. package/source/css/_components/sidebar/logo.styl +0 -111
  370. package/source/css/_components/tag-plugins/about.styl +0 -56
  371. package/source/css/_components/widgets/tree.styl +0 -0
  372. package/source/css/_plugins/scrollreveal.styl +0 -6
  373. package/source/css/_plugins/tianli_gpt.styl +0 -213
  374. package/source/css/plugins/mermaid.styl +0 -137
  375. package/source/js/icons.js +0 -60
  376. package/source/js/services/fcircle.js +0 -35
  377. package/source/js/theme.js +0 -61
package/layout/layout.ejs CHANGED
@@ -1,76 +1,206 @@
1
1
  <%
2
- // 页面类型:索引页面还是内容页面
3
- var page_type = 'index'
4
- if (['post', 'page', 'wiki', null].includes(page.layout)) {
5
- if (!page.nav_tabs) {
6
- page_type = 'content'
7
- }
2
+ var pageConfig = content_config(page)
3
+ var isOrdinaryPost = page.layout === 'post' && pageConfig.collection?.profile !== 'topic'
4
+ var activeViewModel = (isOrdinaryPost || pageConfig.collection?.profile === 'topic')
5
+ ? post_view_model(page)
6
+ : page.viewModel
7
+ var activeProfile = activeViewModel?.collection?.profile
8
+ if (isOrdinaryPost && (activeProfile !== 'post' || activeViewModel?.render == null)) {
9
+ throw new Error(`Stellar v2: 普通 Post ${page.source || page.path || '<unknown>'} 缺少合法 PageViewModel.render`)
8
10
  }
9
- // 文章类型:技术类文章/文学类文章
10
- var article_type = theme.article.type
11
- if (page_type == 'index') {
12
- article_type = undefined
13
- } else if (page.type?.length > 0) {
14
- article_type = page.type
15
- } else if (theme.topic.tree[page.topic]?.type != null) {
16
- article_type = theme.topic.tree[page.topic]?.type
17
- } else if (theme.wiki.tree[page.wiki]?.type != null) {
18
- article_type = theme.wiki.tree[page.wiki]?.type
11
+ var isWikiPage = pageConfig.collection?.profile === 'wiki'
12
+ if (isWikiPage && (activeProfile !== 'wiki' || activeViewModel?.render == null)) {
13
+ throw new Error(`Stellar v2: Wiki 页面 ${page.source || page.path || '<unknown>'} 缺少合法 PageViewModel.render`)
19
14
  }
20
- // 是否缩进
21
- var indent = false
22
- if (page.indent != null) {
23
- indent = page.indent
24
- } else if (theme.topic.tree[page.topic]?.indent != null) {
25
- indent = theme.topic.tree[page.topic]?.indent
26
- } else if (theme.wiki.tree[page.wiki]?.indent != null) {
27
- indent = theme.wiki.tree[page.wiki]?.indent
28
- } else if (theme.article.indent != null) {
29
- indent = theme.article.indent
30
- } else {
31
- indent = article_type === 'story'
15
+ var isTopicPage = pageConfig.collection?.profile === 'topic'
16
+ if (isTopicPage && (activeProfile !== 'topic' || activeViewModel?.render == null)) {
17
+ throw new Error(`Stellar v2: Topic 页面 ${page.source || page.path || '<unknown>'} 缺少合法 PageViewModel.render`)
18
+ }
19
+ var isNotebookPage = pageConfig.collection?.profile === 'notebook'
20
+ if (isNotebookPage && (activeProfile !== 'notebook' || activeViewModel?.render == null)) {
21
+ throw new Error(`Stellar v2: Notebook 页面 ${page.source || page.path || '<unknown>'} 缺少合法 PageViewModel.render`)
22
+ }
23
+ var renderViewModel = ['post', 'wiki', 'topic', 'notebook'].includes(activeProfile) ? activeViewModel : null
24
+ var appearance = stellar_config('appearance')
25
+ var html = ''
26
+
27
+ function siteBackground(enabled) {
28
+ return enabled ? '<div class="site-background"><div class="site-background__blur"></div></div>' : ''
29
+ }
30
+
31
+ function coverSlot(viewModel) {
32
+ var coverBody = viewModel ? partial('_partial/cover/index', {viewModel: viewModel}).trim() : ''
33
+ return `<div id="site-cover" class="site-cover">${coverBody}</div>`
34
+ }
35
+
36
+ function regionSlot(slot, state, viewModel) {
37
+ if (!state || state.enabled === false) return ''
38
+ var widgetBody = partial('_partial/regions/widgets', {
39
+ region: slot,
40
+ state: state,
41
+ widgets: state.widgets,
42
+ viewModel: viewModel || null
43
+ }).trim()
44
+ if (!widgetBody) return ''
45
+ return partial('_partial/primitives/region', {
46
+ slot: slot,
47
+ body: widgetBody
48
+ })
32
49
  }
33
50
 
34
- var site_background = ''
35
- if (theme.style.site && theme.style.site['background-image']) {
36
- site_background += `<div class="sitebg">`
37
- site_background += `<div class="siteblur"></div>`
38
- site_background += `</div>`
51
+ function shellDocument(options) {
52
+ return partial('_partial/primitives/shell', {
53
+ documentModel: options.documentModel,
54
+ pageModel: options.pageModel,
55
+ head: options.head,
56
+ bodyBegin: options.bodyBegin,
57
+ siteBackground: options.siteBackground,
58
+ cover: options.cover,
59
+ regions: options.regions,
60
+ main: options.main,
61
+ controls: partial('_partial/menubtn'),
62
+ overlays: options.searchEnabled ? partial('_partial/search/dialog') : '',
63
+ scripts: options.scripts
64
+ })
39
65
  }
40
66
 
41
- var html = `<!DOCTYPE html>`
42
- if (theme.style.prefers_theme === 'auto') {
43
- html += `<html lang="${page.lang}">`
67
+ function regionsContainSearch(regions) {
68
+ if (!stellar_config('search.provider')) return false
69
+ function menuHasSearch(menu) {
70
+ return Array.isArray(menu) && menu.some(function(item) {
71
+ return item?.type === 'search'
72
+ })
73
+ }
74
+ function brandHasContent(brand) {
75
+ return brand && brand !== false && (brand.name || brand.image?.src)
76
+ }
77
+ var collectionProfile = renderViewModel?.collection?.profile
78
+ || (page.notebookIndex?.mode === 'notes' ? 'notebook' : null)
79
+ return Object.entries(regions || {}).some(function(entry) {
80
+ var slot = entry[0]
81
+ var region = entry[1]
82
+ if (region?.enabled === false) return false
83
+ if (slot === 'leftbar' && ['wiki', 'notebook', 'topic'].includes(collectionProfile) && brandHasContent(region.brand)) return true
84
+ if (slot === 'leftbar') return menuHasSearch(region?.menu)
85
+ if (slot !== 'topbar' || !menuHasSearch(region?.menu)) return false
86
+ return Array.isArray(region?.widgets) && region.widgets.some(function(widget) {
87
+ return widget?.id === 'menu' || widget?.layout === 'menu'
88
+ })
89
+ })
90
+ }
91
+
92
+ if (renderViewModel) {
93
+ var render = renderViewModel.render
94
+ report_region_warnings(render.layout.regionWarnings)
95
+ var regionState = {
96
+ topbar: render.layout.topbar,
97
+ leftbar: render.layout.leftbar,
98
+ rightbar: render.layout.rightbar
99
+ }
100
+ var topbarRegion = regionSlot('topbar', regionState.topbar, renderViewModel)
101
+ var mainBody = ''
102
+ if (showMobileBrand(page, {profileKey: activeProfile}) && !topbarRegion) {
103
+ mainBody += partial('_partial/sidebar/brand', {
104
+ placement: 'main',
105
+ brandModel: regionState.topbar?.brand,
106
+ viewModel: renderViewModel
107
+ })
108
+ }
109
+ mainBody += body + partial('_partial/main/footer')
110
+ html = shellDocument({
111
+ documentModel: {
112
+ language: render.document.language,
113
+ preferredTheme: render.document.preferredTheme
114
+ },
115
+ pageModel: {
116
+ pageType: render.layout.pageType,
117
+ layout: renderViewModel.item.layout,
118
+ articleStyle: render.layout.articleStyle,
119
+ indent: render.layout.indent
120
+ },
121
+ head: partial('_partial/head', {viewModel: renderViewModel}),
122
+ bodyBegin: stellar_inject('bodyBegin', render.document.bodyBeginInject),
123
+ siteBackground: siteBackground(render.layout.siteBackground),
124
+ cover: coverSlot(renderViewModel),
125
+ regions: {
126
+ topbar: topbarRegion,
127
+ leftbar: regionSlot('leftbar', regionState.leftbar, renderViewModel),
128
+ rightbar: regionSlot('rightbar', regionState.rightbar, renderViewModel)
129
+ },
130
+ searchEnabled: regionsContainSearch(regionState),
131
+ main: mainBody,
132
+ scripts: partial('_partial/scripts', {viewModel: renderViewModel})
133
+ })
44
134
  } else {
45
- html += `<html lang="${page.lang}" data-theme="${theme.style.prefers_theme}">`
135
+ var notebookIndex = page.notebookIndex?.mode === 'notes' ? page.notebookIndex.collection : null
136
+ var pageType = ['post', 'page', 'wiki', 'settings', null].includes(page.layout) ? 'content' : 'index'
137
+ var articleDefaults = stellar_config('article')
138
+ var articleStyle = articleDefaults.style
139
+ if (pageType === 'index') {
140
+ articleStyle = undefined
141
+ } else if (pageConfig.article?.style?.length > 0) {
142
+ articleStyle = pageConfig.article.style
143
+ }
144
+ var paragraphIndent = pageConfig.article?.paragraphIndent
145
+ || articleDefaults.paragraphIndent
146
+ || 'auto'
147
+ var indent = paragraphIndent === 'always' || (paragraphIndent === 'auto' && articleStyle === 'story')
148
+ var profileKey = 'page'
149
+ var collectionRegions = null
150
+ if (is_home()) {
151
+ profileKey = 'home'
152
+ } else if (page.layout === 'notebooks') {
153
+ profileKey = 'notebooks'
154
+ } else if (page.layout === 'notes') {
155
+ profileKey = 'notebook'
156
+ collectionRegions = notebookIndex?.layout
157
+ } else if (is_category() || is_tag() || is_archive() || ['categories', 'tags', 'archives'].includes(page.layout)) {
158
+ profileKey = 'blogIndex'
159
+ } else if (page.layout === 'index_topic') {
160
+ profileKey = 'blogIndex'
161
+ } else if (page.layout === 'index_wiki') {
162
+ profileKey = 'wikiIndex'
163
+ } else if (page.layout === '404') {
164
+ profileKey = 'error'
165
+ } else if (page.layout === 'settings') {
166
+ profileKey = 'settings'
167
+ }
168
+ var mobileBrandVisible = showMobileBrand(page, {profileKey: profileKey})
169
+ var pageRegions = region_layout(profileKey, collectionRegions, pageConfig)
170
+ var topbarRegion = regionSlot('topbar', pageRegions.topbar)
171
+ var mainBody = ''
172
+ if (mobileBrandVisible && !topbarRegion) {
173
+ mainBody += partial('_partial/sidebar/brand', {
174
+ placement: 'main',
175
+ brandModel: pageRegions.topbar?.brand
176
+ })
177
+ }
178
+ mainBody += body
179
+ mainBody += partial('_partial/main/footer')
180
+ html = shellDocument({
181
+ documentModel: {
182
+ language: page.lang,
183
+ preferredTheme: appearance.colorScheme
184
+ },
185
+ pageModel: {
186
+ pageType: pageType,
187
+ layout: page.layout,
188
+ articleStyle: articleStyle,
189
+ indent: indent
190
+ },
191
+ head: partial('_partial/head'),
192
+ bodyBegin: stellar_inject('bodyBegin', pageConfig.inject?.bodyBegin),
193
+ siteBackground: siteBackground(appearance.backgrounds.page.image),
194
+ cover: coverSlot(),
195
+ regions: {
196
+ topbar: topbarRegion,
197
+ leftbar: regionSlot('leftbar', pageRegions.leftbar),
198
+ rightbar: regionSlot('rightbar', pageRegions.rightbar)
199
+ },
200
+ searchEnabled: regionsContainSearch(pageRegions),
201
+ main: mainBody,
202
+ scripts: partial('_partial/scripts')
203
+ })
46
204
  }
47
- html += partial('_partial/head')
48
- html += `<body>`
49
- html += site_background
50
- html += `<div id="l_cover">${partial('_partial/cover/index').trim()}</div>`
51
- html += `<div class="l_body ${page_type}" id="start" layout="${page.layout}" type="${article_type}" ${indent ? 'text-indent' : ''}>`
52
- var leftbarSurface = theme.style.leftbar?.['ui-style'] === 'card' ? 'card' : 'glass'
53
- html += `<aside class="l_left${leftbarSurface === 'card' ? ' leftbar-card' : ''}" data-ui-surface="${leftbarSurface}">`
54
- html += `<div class="sidebg"></div>`
55
- html += `<div class="leftbar-container${theme.style.leftbar?.blur ? ' leftbar-blur' : ''}">`
56
- html += partial('_partial/sidebar/index_leftbar')
57
- html += `</div>`
58
- html += `</aside>`
59
- html += `<div class="l_main" id="main" data-ui-surface="content">`
60
- html += partial('_partial/sidebar/logo', {where: 'main'})
61
- html += body
62
- html += partial('_partial/main/footer')
63
- html += `<div class="main-mask" onclick="sidebar.dismiss()"></div>`
64
- html += `</div>`
65
- html += `<aside class="l_right" data-ui-surface="sidebar">`
66
- html += partial('_partial/sidebar/index_rightbar').trim()
67
- html += `</aside>`
68
- html += partial('_partial/menubtn')
69
- html += `</div>`
70
- html += `<div class="scripts">`
71
- html += partial('_partial/scripts')
72
- html += `</div>`
73
- html += `</body>`
74
- html += `</html>`
75
205
  %>
76
206
  <%- html %>
@@ -1,9 +1,9 @@
1
1
  <%# 笔记本列表页主体部分 %>
2
- <% for (const notebook of Object.values(theme.notebooks.tree)) { %>
2
+ <% for (var notebook of page.notebookIndex.items) { %>
3
3
  <div class="post-list wiki">
4
4
  <div class="post-card-wrap<%= scrollreveal(' ') %>">
5
- <a class="post-card wiki card-hover card-hover--spotlight card-hover--tilt" href="<%= pretty_url(notebook.base_dir) %>">
6
- <%- include('_partial/main/notebook/notebook_card', { notebook: notebook }) %>
5
+ <a class="<%- ui_classes('post-card wiki', 'hoverCard') %>" href="<%= pretty_url(notebook.href) %>">
6
+ <%- include('_partial/main/notebook/notebook_card', { render: {listing: notebook} }) %>
7
7
  </a>
8
8
  </div>
9
9
  </div>
package/layout/notes.ejs CHANGED
@@ -1,12 +1,12 @@
1
1
  <%# 笔记列表页主体部分 %>
2
2
  <div class="post-list post">
3
- <% page.posts.each(post => { %>
3
+ <% page.notebookIndex.items.forEach(post => { %>
4
4
  <div class="post-card-wrap<%= scrollreveal(' ') %>">
5
5
  <a
6
- class="post-card post card-hover card-hover--spotlight card-hover--tilt"
7
- href="<%= pretty_url(post.link || post.path) %><%= page.activeTag ? `?tag=${page.activeTag}` : '' %>"
6
+ class="<%- ui_classes('post-card post', 'hoverCard') %>"
7
+ href="<%= pretty_url(post.href) %><%= page.notebookIndex.activeTag ? `?tag=${page.notebookIndex.activeTag}` : '' %>"
8
8
  >
9
- <%- include('_partial/main/notebook/note_card', { note: post }) %>
9
+ <%- include('_partial/main/notebook/note_card', { render: {listing: post} }) %>
10
10
  </a>
11
11
  </div>
12
12
  <% }) %>
package/layout/page.ejs CHANGED
@@ -1,30 +1,27 @@
1
1
  <%
2
- const { layout } = page
3
- // 是否使用 Heti 布局插件
4
- const isUsingHeti = theme.plugins.heti?.enable
5
-
6
- const notebook = theme.notebooks.tree[page.notebook]
7
- if (notebook) {
8
- page.menu_id ??= notebook.menu_id
9
- page.license ??= notebook.license
10
- page.share ??= notebook.share
2
+ var pageConfig = content_config(page)
3
+ var registeredProfile = pageConfig.collection?.profile
4
+ var postViewModel = page.layout === 'post' && (registeredProfile == null || registeredProfile === 'topic')
5
+ ? post_view_model(page)
6
+ : null
7
+ var wikiViewModel = page.viewModel?.collection?.profile === 'wiki' ? page.viewModel : null
8
+ var notebookViewModel = page.viewModel?.collection?.profile === 'notebook' ? page.viewModel : null
9
+ var requiredProfile = page.layout === 'post' ? (registeredProfile === 'topic' ? 'topic' : 'post') : registeredProfile
10
+ var activeViewModel = postViewModel || wikiViewModel || notebookViewModel
11
+ if (['post', 'wiki', 'topic', 'notebook'].includes(requiredProfile) && activeViewModel?.collection?.profile !== requiredProfile) {
12
+ throw new Error(`Stellar v2: ${requiredProfile} 页面 ${page.source || page.path || '<unknown>'} 缺少 PageViewModel`)
11
13
  }
14
+ // 是否使用 Heti 布局插件
15
+ const isUsingHeti = stellar_config('features.heti.enabled')
12
16
 
13
- // 默认的 menu_id
14
- if (page.menu_id == null) {
15
- if (page.wiki?.length > 0) {
16
- page.menu_id = theme.site_tree.wiki.menu_id
17
- } else if (page.topic?.length > 0) {
18
- page.menu_id = theme.site_tree.topic.menu_id
19
- } else {
20
- page.menu_id = theme.site_tree.post.menu_id
21
- }
17
+ // 默认主导航菜单
18
+ if (!postViewModel && !wikiViewModel && !notebookViewModel) page.navigation = {
19
+ menu: pageConfig.activeMenu,
20
+ breadcrumb: pageConfig.breadcrumb
22
21
  }
23
- // 默认的 title
24
- if (page.title == null) {
25
- if (page.wiki) {
26
- page.title = __('btn.wiki')
27
- }
22
+ if (!postViewModel && !wikiViewModel && !notebookViewModel && page.navigation.menu == null) {
23
+ var profiles = stellar_config('profiles')
24
+ page.navigation.menu = profiles.page.activeMenu
28
25
  }
29
26
 
30
27
  function articleClass() {
@@ -35,39 +32,87 @@ function articleClass() {
35
32
  return str
36
33
  }
37
34
 
38
- function layoutDiv() {
35
+ function postArticleClass(article) {
36
+ var str = `md-text content${scrollreveal(' ')}`
37
+ if (article.heti) str += ' heti'
38
+ return str
39
+ }
40
+
41
+ function postLayoutDiv() {
42
+ var item = postViewModel.item
43
+ var article = postViewModel.render.article
39
44
  var el = ''
40
- if (page.nav_tabs) {
41
- el += partial('_partial/main/navbar/nav_tabs_blog')
45
+ if (item.presentation.banner?.headline || item.title || item.content.length > 0) {
46
+ el += partial('_partial/main/navbar/article_banner', {viewModel: postViewModel})
42
47
  }
43
- if (page.h1 || page.title || (page.content && page.content.length > 0)) {
44
- el += partial('_partial/main/navbar/article_banner')
48
+ el += `<article class="${postArticleClass(article)}">`
49
+ el += item.content
50
+ el += '</article>'
51
+ el += partial('_partial/main/article/post_tags', {tags: article.tags})
52
+ el += partial('_partial/main/article/share', {share: article.footer.share})
53
+ el += partial('_partial/main/article/post_footer', {footer: article.footer})
54
+ el += partial('_partial/main/article/post_read_next', {
55
+ previous: article.previous,
56
+ next: article.next
57
+ })
58
+ el += partial('_partial/main/article/post_related', {related: article.related})
59
+ el += partial('_partial/comments/layout', {comments: article.comments})
60
+ return el
61
+ }
62
+
63
+ function wikiLayoutDiv() {
64
+ var item = wikiViewModel.item
65
+ var article = wikiViewModel.render.article
66
+ var el = ''
67
+ if (article.banner?.headline || item.title || item.content.length > 0 || article.readmeHtml.length > 0) {
68
+ el += partial('_partial/main/navbar/article_banner', {viewModel: wikiViewModel})
45
69
  }
46
- el += `<article class="${articleClass()}">`
47
- if (page.content && String(page.content).trim().length > 0) {
48
- el += page.content
49
- } else {
50
- // wiki 项目首页正文为空(剪裁空白后)且配置了 repo 时,
51
- // 以该仓库 README.md 作为主页正文(应用层 helper,复用底层远程 md 渲染组件)
52
- el += wiki_readme_html(theme.wiki.tree[page.wiki], page)
70
+ var cls = `md-text content${scrollreveal(' ')}`
71
+ if (article.heti) cls += ' heti'
72
+ el += `<article class="${cls}">`
73
+ el += item.content.trim().length > 0 ? item.content : article.readmeHtml
74
+ el += '</article>'
75
+ el += partial('_partial/main/article/share', {share: article.footer.share})
76
+ el += partial('_partial/main/article/post_footer', {footer: article.footer})
77
+ el += partial('_partial/main/article/post_read_next', {
78
+ previous: article.previous,
79
+ next: article.next,
80
+ previousLabel: __('meta.prev'),
81
+ nextLabel: __('meta.next')
82
+ })
83
+ el += partial('_partial/comments/layout', {comments: article.comments})
84
+ return el
85
+ }
86
+
87
+ function notebookLayoutDiv() {
88
+ var item = notebookViewModel.item
89
+ var article = notebookViewModel.render.article
90
+ var el = ''
91
+ if (article.banner?.headline || item.title || item.content.length > 0) {
92
+ el += partial('_partial/main/navbar/article_banner', {viewModel: notebookViewModel})
53
93
  }
54
- if (notebook) {
55
- el += partial('_partial/main/notebook/note_tags', { notebook: notebook })
94
+ el += `<article class="${postArticleClass(article)}">`
95
+ el += item.content
96
+ el += partial('_partial/main/notebook/note_tags', {tags: article.tags})
97
+ el += '</article>'
98
+ el += partial('_partial/main/article/share', {share: article.footer.share})
99
+ el += partial('_partial/main/article/post_footer', {footer: article.footer})
100
+ el += partial('_partial/comments/layout', {comments: article.comments})
101
+ return el
102
+ }
103
+
104
+ function layoutDiv() {
105
+ if (postViewModel) return postLayoutDiv()
106
+ if (wikiViewModel) return wikiLayoutDiv()
107
+ if (notebookViewModel) return notebookLayoutDiv()
108
+ var el = ''
109
+ if (pageConfig.banner?.headline || page.title || (page.content && page.content.length > 0)) {
110
+ el += partial('_partial/main/navbar/article_banner')
56
111
  }
112
+ el += `<article class="${articleClass()}">`
113
+ if (page.content && String(page.content).trim().length > 0) el += page.content
57
114
  el += `</article>`
58
- if (layout === 'post' || page.wiki || notebook) {
59
- if (layout === 'post' && theme.article.tags) {
60
- el += partial('_partial/main/article/article_tags')
61
- }
62
- el += partial('_partial/main/article/article_footer')
63
- }
64
- if (layout === 'post' || page.wiki) {
65
- el += partial('_partial/main/article/read_next')
66
- }
67
- if (layout === 'post') {
68
- el += partial('_partial/main/article/related_posts')
69
- }
70
- el += partial('_partial/comments/layout')
115
+ el += partial('_partial/comments/layout', {comments: comments_model(page)})
71
116
  return el
72
117
  }
73
118
  %>
@@ -0,0 +1,109 @@
1
+ <%
2
+ page.robots = 'noindex,nofollow'
3
+ var provider = stellar_config('comments.provider') || ''
4
+ var providerSupported = ['artalk', 'waline', 'twikoo'].includes(String(provider).toLowerCase())
5
+ var settingsConfig = stellar_config('profiles.settings') || {}
6
+ var aboutItems = settingsConfig.about?.items || []
7
+ var cacheItems = [
8
+ { id: 'search', label: __('settings.cache.search') },
9
+ { id: 'dynamic', label: __('settings.cache.dynamic') },
10
+ { id: 'all', label: __('settings.cache.all') }
11
+ ]
12
+ var fallbackAvatar = stellar_config('fallbacks.avatar')
13
+ function linkAttributes(url) {
14
+ return url.includes('://')
15
+ ? ' target="_blank" rel="external nofollow noopener noreferrer"'
16
+ : ' rel="noopener noreferrer"'
17
+ }
18
+ %>
19
+ <article class="md-text content settings-page"
20
+ data-provider="<%- escape_html(provider) %>"
21
+ data-fallback-avatar="<%- escape_html(url_for(fallbackAvatar)) %>"
22
+ data-message-success="<%- escape_html(__('settings.result.success')) %>"
23
+ data-message-partial="<%- escape_html(__('settings.result.partial')) %>"
24
+ data-message-failure="<%- escape_html(__('settings.result.failure')) %>"
25
+ data-validation-name="<%- escape_html(__('settings.validation.name')) %>"
26
+ data-validation-email="<%- escape_html(__('settings.validation.email')) %>"
27
+ data-validation-url="<%- escape_html(__('settings.validation.url')) %>">
28
+ <header class="settings-page__header">
29
+ <h1><%- escape_html(__('settings.title')) %></h1>
30
+ </header>
31
+
32
+ <section class="settings-section" aria-labelledby="settings-profile">
33
+ <h2 id="settings-profile"><%- escape_html(__('settings.profile.title')) %></h2>
34
+ <div class="settings-section__body">
35
+ <div class="settings-profile">
36
+ <div class="settings-profile__avatar" aria-label="<%- escape_html(__('settings.profile.avatar')) %>">
37
+ <img data-profile-avatar src="<%- escape_html(url_for(fallbackAvatar)) %>" alt="">
38
+ <span data-profile-avatar-fallback hidden><%- icon('default:profile', '', true) %></span>
39
+ </div>
40
+ <div class="settings-profile__content">
41
+ <% if (!providerSupported) { %>
42
+ <p data-provider-note class="settings-provider-note"><%- escape_html(__('settings.profile.provider_managed', provider || __('settings.profile.provider_unknown'))) %></p>
43
+ <% } else { %>
44
+ <form data-profile-form class="settings-form" novalidate>
45
+ <label>
46
+ <span><%- escape_html(__('settings.profile.nickname')) %></span>
47
+ <input name="name" type="text" maxlength="80" required autocomplete="nickname">
48
+ </label>
49
+ <label>
50
+ <span><%- escape_html(__('settings.profile.email')) %></span>
51
+ <input name="email" type="email" maxlength="254" autocomplete="email">
52
+ </label>
53
+ <label>
54
+ <span><%- escape_html(__('settings.profile.url')) %></span>
55
+ <input name="url" type="url" inputmode="url" autocomplete="url" placeholder="https://">
56
+ </label>
57
+ <div class="settings-actions">
58
+ <button type="submit" class="settings-button settings-button--primary"><%- escape_html(__('settings.profile.save')) %></button>
59
+ <button type="button" class="settings-button" data-profile-logout><%- escape_html(__('settings.profile.logout')) %></button>
60
+ </div>
61
+ </form>
62
+ <p class="settings-result" data-profile-status role="status" aria-live="polite"></p>
63
+ <% } %>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </section>
68
+
69
+ <section class="settings-section" aria-labelledby="settings-cache">
70
+ <h2 id="settings-cache"><%- escape_html(__('settings.cache.title')) %></h2>
71
+ <div class="settings-section__body">
72
+ <dl class="settings-kv settings-cache-list">
73
+ <% cacheItems.forEach(function(item) { %>
74
+ <div class="settings-kv__row">
75
+ <dt><%- escape_html(item.label) %></dt>
76
+ <dd>
77
+ <span class="settings-kv__value" data-cache-size="<%- item.id %>">0 B</span><button type="button" class="settings-kv__action" data-cache-action="<%- item.id %>" aria-label="<%- escape_html(__('settings.cache.clear', item.label)) %>"><span class="ui-icon"><%- icon('default:trash', '', true) %></span></button>
78
+ </dd>
79
+ </div>
80
+ <% }) %>
81
+ </dl>
82
+ <p class="settings-result" data-cache-status role="status" aria-live="polite"></p>
83
+ </div>
84
+ </section>
85
+
86
+ <section class="settings-section" aria-labelledby="settings-about">
87
+ <h2 id="settings-about"><%- escape_html(__('settings.about.title')) %></h2>
88
+ <div class="settings-section__body">
89
+ <% if (aboutItems.length > 0) { %>
90
+ <dl class="settings-kv">
91
+ <% aboutItems.forEach(function(item) {
92
+ var value = settings_value(item.value)
93
+ var target = item.url ? settings_value(item.url) : ''
94
+ var href = target ? url_for(target) : ''
95
+ %>
96
+ <div class="settings-kv__row">
97
+ <dt><%- escape_html(item.key) %></dt>
98
+ <dd>
99
+ <span class="settings-kv__value"><%- escape_html(value) %></span><% if (href) { %><a class="settings-kv__link" href="<%- escape_html(href) %>"<%- linkAttributes(target) %> aria-label="<%- escape_html(__('settings.about.open_link', item.key)) %>"><span class="ui-icon"><%- icon('default:link', '', true) %></span></a><% } %>
100
+ </dd>
101
+ </div>
102
+ <% }) %>
103
+ </dl>
104
+ <% } else { %>
105
+ <p class="settings-empty"><%- escape_html(__('settings.about.empty')) %></p>
106
+ <% } %>
107
+ </div>
108
+ </section>
109
+ </article>
package/layout/tags.ejs CHANGED
@@ -1,13 +1,14 @@
1
1
  <%
2
2
  page.robots = 'noindex,follow';
3
- if (page.menu_id == undefined) {
4
- page.menu_id = 'post';
3
+ page.navigation ||= {}
4
+ if (page.navigation.menu == undefined) {
5
+ page.navigation.menu = stellar_config('profiles.blogIndex.activeMenu');
5
6
  }
6
7
  %>
7
8
  <% if (site.tags.length) { %>
8
9
  <% page.title = __('btn.tags'); %>
9
10
  <% page.layout = 'tags'; %>
10
- <%- partial('_partial/main/navbar/nav_tabs_blog') %>
11
+ <%- partial('_partial/main/listing_nav/blog') %>
11
12
  <div class='post-list'>
12
13
  <article class='<%- scrollreveal("") %>' id='tags'>
13
14
  <% site.tags.sort('length', -1).each(function(tag){ %>
@@ -1,12 +1,16 @@
1
1
  # Third-Party Notices
2
2
 
3
+ This project includes or adapts portions of the following third-party software.
4
+
3
5
  ## React Bits
4
6
 
5
- The Wiki Galaxy WebGL background and Card Hover spotlight layer are adapted
6
- from the Galaxy and Spotlight Card components in
7
- [React Bits](https://github.com/DavidHDev/react-bits).
7
+ - Project: [React Bits](https://github.com/DavidHDev/react-bits)
8
+ - Components: Ferrofluid, Galaxy and Spotlight Card
9
+ - License: MIT
10
+ - Copyright: Copyright (c) 2026 David Haz
11
+ - Usage: Adapted for the Wiki Ferrofluid and Galaxy WebGL backgrounds and Card Hover spotlight layer.
8
12
 
9
- MIT License
13
+ ### MIT License
10
14
 
11
15
  Copyright (c) 2026 David Haz
12
16