erudit 3.0.0-dev.2 → 3.0.0-dev.21

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 (321) hide show
  1. package/app/app.vue +195 -172
  2. package/app/assets/icons/cameo-add.svg +3 -0
  3. package/app/assets/icons/diamond.svg +3 -0
  4. package/app/assets/icons/graduation.svg +3 -0
  5. package/app/components/Avatar.vue +118 -0
  6. package/app/components/EruditLink.vue +17 -0
  7. package/app/components/Loading.vue +23 -23
  8. package/app/components/SiteAside.vue +393 -382
  9. package/app/components/SiteMain.vue +32 -35
  10. package/app/components/ads/Ads.vue +33 -0
  11. package/app/components/ads/AdsBannerAside.vue +61 -0
  12. package/app/components/ads/AdsBannerBottom.vue +22 -0
  13. package/app/components/ads/AdsProviderCustom.vue +35 -0
  14. package/app/components/ads/AdsProviderYandex.vue +91 -0
  15. package/app/components/ads/AdsReplacer.vue +73 -0
  16. package/app/components/aside/AsideListItem.vue +91 -74
  17. package/app/components/aside/AsideMajor.vue +56 -56
  18. package/app/components/aside/AsideMinor.vue +97 -71
  19. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  20. package/app/components/aside/major/PaneSwitch.vue +54 -54
  21. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  22. package/app/components/aside/major/SiteInfo.vue +85 -85
  23. package/app/components/aside/major/panes/Language.vue +79 -79
  24. package/app/components/aside/major/panes/Pages.vue +50 -34
  25. package/app/components/aside/major/panes/Search.vue +11 -11
  26. package/app/components/aside/major/panes/nav/Nav.vue +92 -91
  27. package/app/components/aside/major/panes/nav/NavBook.vue +95 -86
  28. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  29. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  30. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  31. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  32. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  33. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  34. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  35. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  36. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  37. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  38. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -15
  39. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  40. package/app/components/aside/major/panes/other/Other.vue +16 -16
  41. package/app/components/aside/minor/{Contribute.vue → AsideMinorContribute.vue} +175 -145
  42. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  43. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  44. package/app/components/aside/minor/AsideMinorTopLink.vue +66 -67
  45. package/app/components/aside/minor/content/AsideMinorContent.vue +89 -92
  46. package/app/components/aside/minor/contributor/AsideMinorContributor.vue +78 -0
  47. package/app/components/aside/minor/contributor/BookContribution.vue +64 -0
  48. package/app/components/aside/minor/topic/AsideMinorTopic.vue +31 -32
  49. package/app/components/aside/minor/topic/TopicContributors.vue +183 -177
  50. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  51. package/app/components/aside/minor/topic/TopicToc.vue +212 -203
  52. package/app/components/aside/minor/topic/TopicTocItem.vue +19 -31
  53. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  54. package/app/components/bitran/BitranContent.vue +90 -63
  55. package/app/components/bitran/RenderWrapper.vue +10 -10
  56. package/app/components/contributor/ContributorListItem.vue +43 -35
  57. package/app/components/main/MainActionButton.vue +51 -0
  58. package/app/components/main/MainBitranContent.vue +55 -0
  59. package/app/components/main/{utils/Breadcrumb.vue → MainBreadcrumb.vue} +63 -75
  60. package/app/components/main/MainDescription.vue +24 -0
  61. package/app/components/main/MainSection.vue +58 -0
  62. package/app/components/main/MainTitle.vue +76 -0
  63. package/app/components/main/cameo/MainCameo.vue +135 -0
  64. package/app/components/main/cameo/MainCameoData.vue +232 -0
  65. package/app/components/main/content/ContentBreadcrumb.vue +28 -0
  66. package/app/components/main/{utils → content}/ContentDecoration.vue +29 -29
  67. package/app/components/main/{utils → content}/ContentPopover.vue +188 -176
  68. package/app/components/main/{utils → content}/ContentPopovers.vue +111 -105
  69. package/app/components/main/{utils → content}/ContentReferences.vue +70 -70
  70. package/app/components/main/{utils → content}/reference/ReferenceGroup.vue +38 -38
  71. package/app/components/main/{utils → content}/reference/ReferenceItem.vue +70 -68
  72. package/app/components/main/{utils → content}/reference/ReferenceSource.vue +120 -116
  73. package/app/components/main/topic/MainTopic.vue +76 -79
  74. package/app/components/main/topic/TopicPartSwitch.vue +119 -118
  75. package/app/components/preview/Preview.vue +186 -177
  76. package/app/components/preview/PreviewDisplay.vue +139 -139
  77. package/app/components/preview/PreviewFooterAction.vue +73 -73
  78. package/app/components/preview/PreviewLoading.vue +14 -14
  79. package/app/components/preview/PreviewScreen.vue +141 -99
  80. package/app/components/preview/display/Alert.vue +50 -50
  81. package/app/components/preview/display/Custom.vue +18 -18
  82. package/app/components/preview/display/GenericLink.vue +48 -48
  83. package/app/components/preview/display/PageLink.vue +22 -20
  84. package/app/components/preview/display/Unique.vue +46 -49
  85. package/app/components/sponsor/SponsorTier1.vue +89 -0
  86. package/app/components/sponsor/SponsorTier2.vue +109 -0
  87. package/app/components/transition/Fade.vue +19 -19
  88. package/app/components/tree/TreeContainer.vue +11 -11
  89. package/app/components/tree/TreeItem.vue +93 -89
  90. package/app/composables/adsAllowed.ts +11 -0
  91. package/app/composables/asset.ts +12 -0
  92. package/app/composables/bitran.ts +108 -127
  93. package/app/composables/bitranLocation.ts +7 -7
  94. package/app/composables/contentData.ts +38 -36
  95. package/app/composables/contentPage.ts +168 -156
  96. package/app/composables/contentRoute.ts +45 -45
  97. package/app/composables/darkMagic.ts +24 -24
  98. package/app/composables/externalApi.ts +69 -63
  99. package/app/composables/favicon.ts +8 -8
  100. package/app/composables/formatText.ts +99 -86
  101. package/app/composables/head.ts +24 -0
  102. package/app/composables/majorPane.ts +62 -60
  103. package/app/composables/phrases.ts +77 -80
  104. package/app/composables/theme.ts +29 -29
  105. package/app/composables/url.ts +43 -33
  106. package/app/pages/_test/preview.vue +110 -110
  107. package/app/pages/article/[...articleId].vue +3 -3
  108. package/app/pages/book/[...bookId].vue +42 -47
  109. package/app/pages/contributor/[contributorId].vue +227 -0
  110. package/app/pages/contributors.vue +184 -0
  111. package/app/pages/group/[...groupId].vue +53 -65
  112. package/app/pages/index.vue +32 -32
  113. package/app/pages/practice/[...practice].vue +3 -3
  114. package/app/pages/sponsors.vue +95 -0
  115. package/app/pages/summary/[...summaryId].vue +3 -3
  116. package/app/plugins/analytics.ts +95 -0
  117. package/app/plugins/prerender.server.ts +34 -0
  118. package/app/public/favicon/article.svg +5 -5
  119. package/app/public/favicon/default.svg +3 -3
  120. package/app/public/favicon/practice.svg +3 -3
  121. package/app/public/favicon/summary.svg +4 -4
  122. package/app/public/logotype.svg +2 -2
  123. package/app/scripts/_immediate.js +9 -9
  124. package/app/scripts/aside/index.ts +59 -59
  125. package/app/scripts/aside/major/nav.ts +26 -26
  126. package/app/scripts/aside/minor/state.ts +37 -37
  127. package/app/scripts/flag.ts +28 -28
  128. package/app/scripts/og.ts +28 -27
  129. package/app/scripts/preview/build.ts +76 -73
  130. package/app/scripts/preview/data/alert.ts +19 -19
  131. package/app/scripts/preview/data/custom.ts +8 -8
  132. package/app/scripts/preview/data/genericLink.ts +24 -24
  133. package/app/scripts/preview/data/pageLink.ts +23 -20
  134. package/app/scripts/preview/data/unique.ts +69 -70
  135. package/app/scripts/preview/data.ts +24 -24
  136. package/app/scripts/preview/display.ts +37 -37
  137. package/app/scripts/preview/footer.ts +9 -9
  138. package/app/scripts/preview/request.ts +51 -51
  139. package/app/scripts/preview/state.ts +63 -63
  140. package/app/styles/_immediate.css +7 -7
  141. package/app/styles/_util.scss +43 -43
  142. package/app/styles/_utils.scss +44 -44
  143. package/app/styles/app.scss +91 -91
  144. package/app/styles/def/_bp.scss +27 -27
  145. package/app/styles/def/_size.scss +7 -7
  146. package/app/styles/def/_z.scss +5 -5
  147. package/app/styles/normalize.scss +49 -63
  148. package/app/styles/partials/_darkMagic.scss +5 -5
  149. package/app/styles/partials/_fnav.scss +15 -15
  150. package/app/styles/partials/_preview.scss +5 -5
  151. package/bin/erudit.mjs +2 -0
  152. package/const.ts +3 -0
  153. package/globalPath.ts +21 -21
  154. package/globals/bitran.ts +1 -47
  155. package/globals/cameo.ts +5 -0
  156. package/globals/content.ts +27 -22
  157. package/globals/contributor.ts +5 -5
  158. package/globals/erudit.ts +5 -5
  159. package/globals/register.ts +23 -18
  160. package/globals/sponsor.ts +17 -0
  161. package/languages/en.ts +108 -95
  162. package/languages/ru.ts +112 -99
  163. package/module/bitran.ts +66 -34
  164. package/module/config.ts +35 -34
  165. package/module/imports.ts +74 -46
  166. package/module/index.ts +47 -47
  167. package/module/logger.ts +10 -10
  168. package/module/paths.ts +22 -22
  169. package/module/restart.ts +61 -61
  170. package/nuxt.config.ts +126 -112
  171. package/package.json +22 -15
  172. package/server/api/aside/major/nav/bookIds.ts +5 -5
  173. package/server/api/aside/major/nav/bookNav/[...bookId].ts +17 -20
  174. package/server/api/aside/major/nav/global.ts +7 -7
  175. package/server/api/aside/minor/book/[...bookId].ts +18 -0
  176. package/server/api/aside/minor/contributor/[contributorId].ts +18 -0
  177. package/server/api/aside/minor/group/[...groupId].ts +18 -0
  178. package/server/api/aside/minor/news.ts +7 -7
  179. package/server/api/aside/minor/topic.ts +36 -0
  180. package/server/api/bitran/content/[...location].ts +13 -0
  181. package/server/api/bitran/toc/[...location].ts +9 -0
  182. package/server/api/cameo/data/[cameoId].ts +42 -0
  183. package/server/api/cameo/ids.ts +5 -0
  184. package/server/api/content/data.ts +75 -72
  185. package/server/api/contributor/count.ts +6 -6
  186. package/server/api/contributor/list.ts +44 -0
  187. package/server/api/contributor/page/[contributorId].ts +14 -0
  188. package/server/api/fake/content.ts +11 -11
  189. package/server/api/fake/shared/languages.ts +12 -12
  190. package/server/api/language/functions.ts +12 -12
  191. package/server/api/language/phrase/[phraseId].ts +19 -19
  192. package/server/api/language/phraseIds.ts +8 -8
  193. package/server/api/prerender/assets/cameo.ts +14 -0
  194. package/server/api/prerender/assets/contributor.ts +12 -0
  195. package/server/api/prerender/assets/sponsor.ts +13 -0
  196. package/server/api/prerender/cameos.ts +12 -0
  197. package/server/api/prerender/language.ts +9 -0
  198. package/server/api/preview/page/[...parts].ts +78 -51
  199. package/server/api/preview/unique/{[location].ts → [...location].ts} +48 -55
  200. package/server/api/problem/generator/[...path].ts +26 -0
  201. package/server/api/sponsor/cameo/data/[sponsorId].ts +51 -0
  202. package/server/api/sponsor/cameo/ids.ts +5 -0
  203. package/server/api/sponsor/count.ts +5 -0
  204. package/server/api/sponsor/list.ts +36 -0
  205. package/server/plugin/bitran/content.ts +252 -187
  206. package/server/plugin/bitran/{products → elements}/include.ts +229 -230
  207. package/server/plugin/bitran/location.ts +43 -25
  208. package/server/plugin/bitran/toc.ts +94 -83
  209. package/server/plugin/bitran/transpiler.ts +18 -46
  210. package/server/plugin/build/close.ts +12 -10
  211. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  212. package/server/plugin/build/jobs/content/generic.ts +191 -176
  213. package/server/plugin/build/jobs/content/parse.ts +113 -100
  214. package/server/plugin/build/jobs/content/path.ts +6 -6
  215. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  216. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  217. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  218. package/server/plugin/build/jobs/contributors.ts +69 -66
  219. package/server/plugin/build/jobs/language.ts +36 -36
  220. package/server/plugin/build/jobs/nav.ts +345 -210
  221. package/server/plugin/build/process.ts +34 -25
  222. package/server/plugin/build/rebuild.ts +68 -55
  223. package/server/plugin/build/setup.ts +19 -21
  224. package/server/plugin/content/context.ts +119 -112
  225. package/server/plugin/db/entities/Book.ts +7 -7
  226. package/server/plugin/db/entities/Content.ts +45 -49
  227. package/server/plugin/db/entities/Contribution.ts +10 -10
  228. package/server/plugin/db/entities/Contributor.ts +25 -16
  229. package/server/plugin/db/entities/File.ts +10 -0
  230. package/server/plugin/db/entities/Group.ts +14 -14
  231. package/server/plugin/db/entities/Hash.ts +15 -15
  232. package/server/plugin/db/entities/Topic.ts +20 -20
  233. package/server/plugin/db/entities/Unique.ts +21 -21
  234. package/server/plugin/db/reset.ts +12 -0
  235. package/server/plugin/db/setup.ts +49 -34
  236. package/server/plugin/global.ts +18 -18
  237. package/server/plugin/importer.ts +16 -12
  238. package/server/plugin/index.ts +9 -9
  239. package/server/plugin/logger.ts +23 -23
  240. package/server/plugin/nav/node.ts +27 -26
  241. package/server/plugin/nav/utils.ts +179 -129
  242. package/server/plugin/repository/asideMinor.ts +51 -0
  243. package/server/plugin/repository/book.ts +39 -21
  244. package/server/plugin/repository/cameo.ts +16 -0
  245. package/server/plugin/repository/content.ts +240 -238
  246. package/server/plugin/repository/contentId.ts +40 -0
  247. package/server/plugin/repository/contributor.ts +129 -8
  248. package/server/plugin/repository/file.ts +10 -0
  249. package/server/plugin/repository/frontNav.ts +145 -148
  250. package/server/plugin/repository/topic.ts +35 -32
  251. package/server/plugin/sponsor/build.ts +82 -0
  252. package/server/plugin/sponsor/index.ts +5 -0
  253. package/server/plugin/sponsor/repository.ts +56 -0
  254. package/server/routes/asset/[...assetPath].ts +34 -0
  255. package/server/routes/robots.txt.ts +9 -0
  256. package/server/routes/sitemap.xml.ts +103 -0
  257. package/server/tsconfig.json +9 -9
  258. package/shared/aside/minor.ts +55 -50
  259. package/shared/asset.ts +17 -15
  260. package/shared/bitran/content.ts +9 -0
  261. package/shared/bitran/contentId.ts +56 -0
  262. package/shared/bitran/toc.ts +8 -8
  263. package/shared/breadcrumb.ts +7 -0
  264. package/shared/content/bookId.ts +12 -0
  265. package/shared/content/context.ts +9 -9
  266. package/shared/content/data/base.ts +32 -32
  267. package/shared/content/data/index.ts +5 -5
  268. package/shared/content/data/type/book.ts +5 -5
  269. package/shared/content/data/type/group.ts +6 -6
  270. package/shared/content/data/type/topic.ts +11 -11
  271. package/shared/content/previousNext.ts +9 -9
  272. package/shared/contributor.ts +34 -5
  273. package/shared/frontNav.ts +41 -41
  274. package/shared/icons.ts +38 -38
  275. package/shared/image.ts +5 -5
  276. package/shared/link.ts +28 -25
  277. package/shared/popover.ts +8 -0
  278. package/shared/types/language.ts +84 -75
  279. package/shared/utils/objectsEqual.ts +4 -4
  280. package/shared/utils/stringColor.ts +9 -9
  281. package/test/contentId.test.ts +91 -0
  282. package/test/utils/url.test.ts +99 -0
  283. package/tsconfig.json +8 -8
  284. package/utils/contentPath.ts +67 -0
  285. package/utils/ext.ts +41 -0
  286. package/utils/stress.ts +9 -9
  287. package/utils/url.ts +23 -0
  288. package/app/components/ads/BannerTemplate.vue +0 -51
  289. package/app/components/ads/BottomBanner.vue +0 -45
  290. package/app/components/ads/LeftBanner.vue +0 -50
  291. package/app/components/aside/minor/AsideMinorContributor.vue +0 -5
  292. package/app/components/contributor/ContributorAvatar.vue +0 -43
  293. package/app/components/main/utils/ContentDescription.vue +0 -19
  294. package/app/components/main/utils/ContentFlag.vue +0 -15
  295. package/app/components/main/utils/ContentSection.vue +0 -45
  296. package/app/components/main/utils/ContentTitle.vue +0 -39
  297. package/app/composables/bitranContent.ts +0 -37
  298. package/app/pages/members.vue +0 -6
  299. package/app/public/user.svg +0 -10
  300. package/app/scripts/aside/minor/topic.ts +0 -3
  301. package/app/styles/default.scss +0 -83
  302. package/server/api/aside/minor/path.ts +0 -78
  303. package/server/api/bitran/content/[location].ts +0 -7
  304. package/server/api/bitran/toc/[location].ts +0 -7
  305. package/server/plugin/bitran/products/link.ts +0 -116
  306. package/server/plugin/bitran/setup.ts +0 -9
  307. package/server/plugin/content/absoluteId.ts +0 -94
  308. package/shared/bitran/context.ts +0 -8
  309. package/shared/bitran/default.ts +0 -46
  310. package/shared/bitran/link/Link.vue +0 -167
  311. package/shared/bitran/link/factory.ts +0 -24
  312. package/shared/bitran/link/icon.svg +0 -3
  313. package/shared/bitran/link/languages/en.ts +0 -7
  314. package/shared/bitran/link/languages/ru.ts +0 -7
  315. package/shared/bitran/link/renderer.ts +0 -21
  316. package/shared/bitran/link/shared.ts +0 -17
  317. package/shared/bitran/link/target.ts +0 -134
  318. package/shared/bitran/link/transpiler.ts +0 -10
  319. package/shared/bitran/location.ts +0 -166
  320. package/test/bitran/link/target.test.ts +0 -141
  321. package/test/bitran/location.test.ts +0 -143
@@ -1,129 +1,179 @@
1
- import { ERUDIT_SERVER } from '@server/global';
2
- import { isRootNode, type NavNode } from '@server/nav/node';
3
-
4
- export async function walkNav(
5
- step: (node: NavNode) => Promise<void | false>,
6
- from: NavNode | typeof ERUDIT_SERVER.NAV = ERUDIT_SERVER.NAV,
7
- ) {
8
- if (!from) return;
9
-
10
- const stepResult = isRootNode(from) ? true : await step(from);
11
-
12
- if (stepResult !== false)
13
- if (from.children)
14
- for (const child of from.children) await walkNav(step, child);
15
- }
16
-
17
- //
18
- //
19
- //
20
-
21
- export function getNavBookOf(target: string | NavNode): NavNode | undefined {
22
- const id = typeof target === 'string' ? target : target.id;
23
-
24
- if (!id || !ERUDIT_SERVER.NAV_BOOKS) return undefined;
25
-
26
- const idParts = id.split('/');
27
-
28
- while (idParts.length > 0) {
29
- const book = ERUDIT_SERVER.NAV_BOOKS[idParts.join('/')];
30
-
31
- if (book) return book;
32
-
33
- idParts.pop();
34
- }
35
-
36
- return undefined;
37
- }
38
-
39
- export async function getPreviousNextNav(contentId: string) {
40
- let previousNav: NavNode | undefined, nextNav: NavNode | undefined;
41
- let book: NavNode | undefined;
42
- let finish = false;
43
-
44
- await walkNav(async (navNode) => {
45
- if (navNode.id === contentId) {
46
- book = getNavBookOf(navNode);
47
- finish = true;
48
- return;
49
- }
50
-
51
- if (finish && !nextNav) {
52
- nextNav = navNode;
53
- return false;
54
- }
55
-
56
- if (!finish) previousNav = navNode;
57
- });
58
-
59
- if (book) {
60
- //
61
- // Can't lead out of current book (if givent content item is inside the book)
62
- //
63
-
64
- if (previousNav)
65
- if (getNavBookOf(previousNav)?.fullId !== book.fullId)
66
- previousNav = undefined;
67
-
68
- if (nextNav)
69
- if (getNavBookOf(nextNav)?.fullId !== book.fullId)
70
- nextNav = undefined;
71
- } else {
72
- //
73
- // If not inside the book and tries to lead inside a book, then force lead to book's about page
74
- //
75
-
76
- if (previousNav) previousNav = getNavBookOf(previousNav) || previousNav;
77
-
78
- if (nextNav) nextNav = getNavBookOf(nextNav) || nextNav;
79
- }
80
-
81
- return {
82
- previousNav,
83
- nextNav,
84
- };
85
- }
86
-
87
- export async function getNavNode(
88
- contentId: string,
89
- ): Promise<NavNode | undefined> {
90
- let navNode: NavNode | undefined;
91
-
92
- await walkNav(async (_navNode) => {
93
- if (_navNode.id === contentId) {
94
- navNode = _navNode;
95
- return false;
96
- }
97
- });
98
-
99
- return navNode;
100
- }
101
-
102
- export async function getIdsUp(contentId: string): Promise<string[]> {
103
- const startNavNode = await getNavNode(contentId);
104
-
105
- if (!startNavNode) return [];
106
-
107
- const ids: string[] = [];
108
-
109
- let currentNavNode: any = startNavNode;
110
- while (currentNavNode?.id) {
111
- ids.push(currentNavNode.id);
112
- currentNavNode = currentNavNode.parent;
113
- }
114
-
115
- return ids;
116
- }
117
-
118
- export async function isSkipId(contentId: string) {
119
- let hidden = false;
120
-
121
- await walkNav(async (navNode) => {
122
- if (navNode.id === contentId) {
123
- hidden = navNode.skip;
124
- return false;
125
- }
126
- });
127
-
128
- return hidden;
129
- }
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+ import { isRootNode, type NavNode, type RootNavNode } from '@server/nav/node';
3
+
4
+ export async function walkNav(
5
+ step: (node: NavNode) => Promise<void | false>,
6
+ from: NavNode | typeof ERUDIT_SERVER.NAV = ERUDIT_SERVER.NAV,
7
+ ) {
8
+ if (!from) return;
9
+
10
+ const stepResult = isRootNode(from) ? true : await step(from);
11
+
12
+ if (stepResult !== false)
13
+ if (from.children)
14
+ for (const child of from.children) await walkNav(step, child);
15
+ }
16
+
17
+ //
18
+ //
19
+ //
20
+
21
+ export function getNavBookIds(mode: 'full' | 'short'): string[] {
22
+ const bookIds: string[] = [];
23
+
24
+ if (!ERUDIT_SERVER.NAV_BOOKS) {
25
+ return bookIds;
26
+ }
27
+
28
+ for (const navBook of Object.values(ERUDIT_SERVER.NAV_BOOKS)) {
29
+ bookIds.push(mode === 'full' ? navBook.fullId : navBook.shortId);
30
+ }
31
+
32
+ return bookIds;
33
+ }
34
+
35
+ export function getNavBookOf(target: string | NavNode): NavNode | undefined {
36
+ const id = typeof target === 'string' ? target : target.fullId;
37
+
38
+ if (!id || !ERUDIT_SERVER.NAV_BOOKS) {
39
+ return undefined;
40
+ }
41
+
42
+ const idParts = id.split('/');
43
+
44
+ while (idParts.length > 0) {
45
+ const book = ERUDIT_SERVER.NAV_BOOKS[idParts.join('/')];
46
+
47
+ if (book) {
48
+ return book;
49
+ }
50
+
51
+ idParts.pop();
52
+ }
53
+
54
+ return undefined;
55
+ }
56
+
57
+ export async function getPreviousNextNav(contentId: string) {
58
+ let previousNav: NavNode | undefined, nextNav: NavNode | undefined;
59
+ let book: NavNode | undefined;
60
+ let finish = false;
61
+
62
+ await walkNav(async (navNode) => {
63
+ if (navNode.fullId === contentId) {
64
+ book = getNavBookOf(navNode);
65
+ finish = true;
66
+ return;
67
+ }
68
+
69
+ if (finish && !nextNav) {
70
+ nextNav = navNode;
71
+ return false;
72
+ }
73
+
74
+ if (!finish) previousNav = navNode;
75
+ });
76
+
77
+ if (book) {
78
+ //
79
+ // Can't lead out of current book (if givent content item is inside the book)
80
+ //
81
+
82
+ if (previousNav)
83
+ if (getNavBookOf(previousNav)?.fullId !== book.fullId)
84
+ previousNav = undefined;
85
+
86
+ if (nextNav)
87
+ if (getNavBookOf(nextNav)?.fullId !== book.fullId)
88
+ nextNav = undefined;
89
+ } else {
90
+ //
91
+ // If not inside the book and tries to lead inside a book, then force lead to book's about page
92
+ //
93
+
94
+ if (previousNav) previousNav = getNavBookOf(previousNav) || previousNav;
95
+
96
+ if (nextNav) nextNav = getNavBookOf(nextNav) || nextNav;
97
+ }
98
+
99
+ return {
100
+ previousNav,
101
+ nextNav,
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Find navigation node by mixed content ID.
107
+ * It can be full ID, short ID or any combination of present and missing skipped parts.
108
+ */
109
+ export function getNavNode(mixedContentId: string): NavNode {
110
+ const parts = mixedContentId.split('/');
111
+ let foundNode: NavNode | undefined;
112
+
113
+ function search(node: NavNode, partIdx: number): NavNode | undefined {
114
+ const targetIdPart = parts[partIdx];
115
+ const nodeIdPart = node.idPart;
116
+
117
+ if (nodeIdPart === targetIdPart) {
118
+ if (partIdx === parts.length - 1) {
119
+ return node;
120
+ }
121
+
122
+ for (const child of node.children || []) {
123
+ const deepResult = search(child, partIdx + 1);
124
+ if (deepResult) return deepResult;
125
+ }
126
+ }
127
+
128
+ if (node.skip) {
129
+ for (const child of node.children || []) {
130
+ const deepResult = search(child, partIdx);
131
+ if (deepResult) return deepResult;
132
+ }
133
+ }
134
+
135
+ return undefined;
136
+ }
137
+
138
+ for (const child of ERUDIT_SERVER.NAV?.children || []) {
139
+ foundNode = search(child, 0);
140
+ if (foundNode) break;
141
+ }
142
+
143
+ if (!foundNode) {
144
+ throw new Error(
145
+ `Failed to find navigation content node for ID: ${mixedContentId}`,
146
+ );
147
+ }
148
+
149
+ return foundNode;
150
+ }
151
+
152
+ export function getIdsUp(contentId: string): string[] {
153
+ const ids: string[] = [];
154
+ const startNavNode = getNavNode(contentId);
155
+
156
+ if (!startNavNode) return ids;
157
+
158
+ let currentNavNode: NavNode = startNavNode;
159
+
160
+ while (currentNavNode?.idPart) {
161
+ ids.push(currentNavNode.fullId);
162
+ currentNavNode = currentNavNode.parent as NavNode;
163
+ }
164
+
165
+ return ids;
166
+ }
167
+
168
+ export async function isSkipId(contentId: string) {
169
+ let hidden = false;
170
+
171
+ await walkNav(async (navNode) => {
172
+ if (navNode.fullId === contentId) {
173
+ hidden = navNode.skip;
174
+ return false;
175
+ }
176
+ });
177
+
178
+ return hidden;
179
+ }
@@ -0,0 +1,51 @@
1
+ import type { ContentType } from '@erudit-js/cog/schema';
2
+
3
+ import type { NavNode } from '@server/nav/node';
4
+ import { getNavNode } from '@server/nav/utils';
5
+ import {
6
+ getContentContributors,
7
+ getPreviousNext,
8
+ } from '@server/repository/content';
9
+
10
+ import type { AsideMinorContentBase } from '@shared/aside/minor';
11
+
12
+ export function getAsideMinorContentNode(
13
+ type: ContentType,
14
+ rawContentId?: string,
15
+ ) {
16
+ if (!rawContentId) {
17
+ throw createError({
18
+ statusCode: 400,
19
+ message: `Missing "${type}Id" parameter!`,
20
+ });
21
+ }
22
+
23
+ const contentNavNode = getNavNode(rawContentId);
24
+
25
+ if (contentNavNode.type !== type) {
26
+ throw createError({
27
+ statusCode: 400,
28
+ message: `Provided "${rawContentId}" is not a content ${type}!`,
29
+ });
30
+ }
31
+
32
+ return contentNavNode;
33
+ }
34
+
35
+ export async function getAsideMinorContentBase(
36
+ navNode: NavNode,
37
+ ): Promise<Omit<AsideMinorContentBase, 'type'>> {
38
+ const fullContentId = navNode.fullId;
39
+ const shortContentId = navNode.shortId;
40
+ const fsContentDirectory = navNode.fsPath;
41
+ const contributors = await getContentContributors(fullContentId);
42
+ const previousNext = await getPreviousNext(fullContentId);
43
+
44
+ return {
45
+ fullContentId,
46
+ shortContentId,
47
+ fsContentDirectory,
48
+ contributors,
49
+ previousNext,
50
+ };
51
+ }
@@ -1,21 +1,39 @@
1
- import { ERUDIT_SERVER } from '@server/global';
2
- import { getNavBookOf } from '@server/nav/utils';
3
- import { DbContent } from '@server/db/entities/Content';
4
-
5
- export async function getContentBookFor(contentId: string) {
6
- const navBook = getNavBookOf(contentId);
7
-
8
- if (!navBook) return undefined;
9
-
10
- const bookId = navBook.id;
11
-
12
- const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
13
- select: ['title'],
14
- where: { contentId: bookId },
15
- });
16
-
17
- return {
18
- contentId: bookId,
19
- title: dbContent?.title || bookId,
20
- };
21
- }
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+ import { getNavBookOf } from '@server/nav/utils';
3
+ import { DbContent } from '@server/db/entities/Content';
4
+ import { getFullContentId } from './contentId';
5
+
6
+ export async function getContentBookFor(contentId: string) {
7
+ contentId = getFullContentId(contentId);
8
+ const navBook = getNavBookOf(contentId);
9
+
10
+ if (!navBook) return undefined;
11
+
12
+ const bookId = navBook.fullId;
13
+
14
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
15
+ select: ['title'],
16
+ where: { contentId: bookId },
17
+ });
18
+
19
+ return {
20
+ contentId: bookId,
21
+ title: dbContent?.title || bookId,
22
+ };
23
+ }
24
+
25
+ export async function getBookTitleFor(contentId: string) {
26
+ contentId = getFullContentId(contentId);
27
+ const navBook = getNavBookOf(contentId);
28
+
29
+ if (!navBook) return undefined;
30
+
31
+ const bookId = navBook.fullId;
32
+
33
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
34
+ select: ['title'],
35
+ where: { contentId: bookId },
36
+ });
37
+
38
+ return dbContent?.title || bookId;
39
+ }
@@ -0,0 +1,16 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import { PROJECT_DIR } from '#erudit/globalPaths';
3
+
4
+ export async function getCameoIds() {
5
+ try {
6
+ const dirents = await readdir(`${PROJECT_DIR}/cameos`, {
7
+ withFileTypes: true,
8
+ });
9
+
10
+ return dirents
11
+ .filter((dirent) => dirent.isDirectory())
12
+ .map((dirent) => dirent.name);
13
+ } catch {
14
+ return [];
15
+ }
16
+ }