erudit 2.0.0-dev.7

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 (314) hide show
  1. package/.nuxtrc +1 -0
  2. package/app/app.vue +172 -0
  3. package/app/assets/icons/alert.svg +3 -0
  4. package/app/assets/icons/angle-right.svg +3 -0
  5. package/app/assets/icons/arrow-in-text.svg +3 -0
  6. package/app/assets/icons/arrow-left.svg +3 -0
  7. package/app/assets/icons/arrow-up-to-right.svg +3 -0
  8. package/app/assets/icons/aside-open.svg +3 -0
  9. package/app/assets/icons/asterisk.svg +3 -0
  10. package/app/assets/icons/book-question.svg +3 -0
  11. package/app/assets/icons/book.svg +3 -0
  12. package/app/assets/icons/bug.svg +3 -0
  13. package/app/assets/icons/chip.svg +3 -0
  14. package/app/assets/icons/circle-help.svg +3 -0
  15. package/app/assets/icons/construction.svg +3 -0
  16. package/app/assets/icons/cross.svg +3 -0
  17. package/app/assets/icons/draw.svg +3 -0
  18. package/app/assets/icons/ellipsis-vertical.svg +3 -0
  19. package/app/assets/icons/file-check.svg +3 -0
  20. package/app/assets/icons/file-lines.svg +3 -0
  21. package/app/assets/icons/file-star.svg +3 -0
  22. package/app/assets/icons/folder-open.svg +3 -0
  23. package/app/assets/icons/folder.svg +3 -0
  24. package/app/assets/icons/globe.svg +3 -0
  25. package/app/assets/icons/house.svg +3 -0
  26. package/app/assets/icons/link-external.svg +3 -0
  27. package/app/assets/icons/link.svg +3 -0
  28. package/app/assets/icons/moon.svg +3 -0
  29. package/app/assets/icons/outline/book.svg +3 -0
  30. package/app/assets/icons/outline/file-lines.svg +3 -0
  31. package/app/assets/icons/pirate.svg +3 -0
  32. package/app/assets/icons/plus-circle.svg +3 -0
  33. package/app/assets/icons/plus.svg +3 -0
  34. package/app/assets/icons/puzzle.svg +3 -0
  35. package/app/assets/icons/search.svg +3 -0
  36. package/app/assets/icons/shuffle.svg +3 -0
  37. package/app/assets/icons/star.svg +3 -0
  38. package/app/assets/icons/sun-moon.svg +3 -0
  39. package/app/assets/icons/sun.svg +3 -0
  40. package/app/assets/icons/user.svg +3 -0
  41. package/app/assets/icons/users.svg +3 -0
  42. package/app/components/Loading.vue +23 -0
  43. package/app/components/SiteAside.vue +382 -0
  44. package/app/components/SiteMain.vue +35 -0
  45. package/app/components/ads/BannerTemplate.vue +51 -0
  46. package/app/components/ads/BottomBanner.vue +45 -0
  47. package/app/components/ads/LeftBanner.vue +50 -0
  48. package/app/components/aside/AsideListItem.vue +74 -0
  49. package/app/components/aside/AsideMajor.vue +56 -0
  50. package/app/components/aside/AsideMinor.vue +71 -0
  51. package/app/components/aside/major/PaneContentScroll.vue +23 -0
  52. package/app/components/aside/major/PaneSwitch.vue +54 -0
  53. package/app/components/aside/major/PaneSwitchButton.vue +63 -0
  54. package/app/components/aside/major/SiteInfo.vue +85 -0
  55. package/app/components/aside/major/panes/Language.vue +79 -0
  56. package/app/components/aside/major/panes/Pages.vue +34 -0
  57. package/app/components/aside/major/panes/Search.vue +3 -0
  58. package/app/components/aside/major/panes/nav/Nav.vue +91 -0
  59. package/app/components/aside/major/panes/nav/NavBook.vue +86 -0
  60. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -0
  61. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -0
  62. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -0
  63. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -0
  64. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -0
  65. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -0
  66. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -0
  67. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -0
  68. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -0
  69. package/app/components/aside/major/panes/other/ItemContent.vue +29 -0
  70. package/app/components/aside/major/panes/other/ItemGenerator.vue +15 -0
  71. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -0
  72. package/app/components/aside/major/panes/other/Other.vue +16 -0
  73. package/app/components/aside/minor/AsideMinorContributor.vue +5 -0
  74. package/app/components/aside/minor/AsideMinorNews.vue +11 -0
  75. package/app/components/aside/minor/AsideMinorPane.vue +16 -0
  76. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -0
  77. package/app/components/aside/minor/Contribute.vue +145 -0
  78. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -0
  79. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -0
  80. package/app/components/aside/minor/topic/TopicContributors.vue +177 -0
  81. package/app/components/aside/minor/topic/TopicNav.vue +49 -0
  82. package/app/components/aside/minor/topic/TopicToc.vue +202 -0
  83. package/app/components/aside/minor/topic/TopicTocItem.vue +31 -0
  84. package/app/components/aside/utils/AsideOverlayPane.vue +40 -0
  85. package/app/components/bitran/BitranContent.vue +64 -0
  86. package/app/components/bitran/RenderWrapper.vue +12 -0
  87. package/app/components/contributor/ContributorAvatar.vue +43 -0
  88. package/app/components/contributor/ContributorListItem.vue +35 -0
  89. package/app/components/main/topic/MainTopic.vue +79 -0
  90. package/app/components/main/topic/TopicPartSwitch.vue +118 -0
  91. package/app/components/main/utils/Breadcrumb.vue +75 -0
  92. package/app/components/main/utils/ContentDecoration.vue +29 -0
  93. package/app/components/main/utils/ContentDescription.vue +20 -0
  94. package/app/components/main/utils/ContentFlag.vue +16 -0
  95. package/app/components/main/utils/ContentPopover.vue +176 -0
  96. package/app/components/main/utils/ContentPopovers.vue +105 -0
  97. package/app/components/main/utils/ContentReferences.vue +76 -0
  98. package/app/components/main/utils/ContentSection.vue +42 -0
  99. package/app/components/main/utils/ContentTitle.vue +37 -0
  100. package/app/components/main/utils/reference/ReferenceGroup.vue +41 -0
  101. package/app/components/main/utils/reference/ReferenceItem.vue +64 -0
  102. package/app/components/main/utils/reference/ReferenceSource.vue +110 -0
  103. package/app/components/preview/Preview.vue +177 -0
  104. package/app/components/preview/PreviewDisplay.vue +139 -0
  105. package/app/components/preview/PreviewFooterAction.vue +73 -0
  106. package/app/components/preview/PreviewLoading.vue +15 -0
  107. package/app/components/preview/PreviewScreen.vue +99 -0
  108. package/app/components/preview/display/Alert.vue +50 -0
  109. package/app/components/preview/display/Custom.vue +18 -0
  110. package/app/components/preview/display/GenericLink.vue +48 -0
  111. package/app/components/preview/display/PageLink.vue +20 -0
  112. package/app/components/preview/display/Unique.vue +49 -0
  113. package/app/components/transition/Fade.vue +22 -0
  114. package/app/components/tree/TreeContainer.vue +12 -0
  115. package/app/components/tree/TreeItem.vue +89 -0
  116. package/app/composables/bitran.ts +132 -0
  117. package/app/composables/bitranContent.ts +36 -0
  118. package/app/composables/bitranLocation.ts +7 -0
  119. package/app/composables/contentData.ts +36 -0
  120. package/app/composables/contentPage.ts +156 -0
  121. package/app/composables/contentRoute.ts +45 -0
  122. package/app/composables/darkMagic.ts +24 -0
  123. package/app/composables/externalApi.ts +63 -0
  124. package/app/composables/favicon.ts +8 -0
  125. package/app/composables/formatText.ts +86 -0
  126. package/app/composables/majorPane.ts +60 -0
  127. package/app/composables/phrases.ts +80 -0
  128. package/app/composables/theme.ts +29 -0
  129. package/app/composables/url.ts +33 -0
  130. package/app/pages/_test/preview.vue +110 -0
  131. package/app/pages/article/[...articleId].vue +3 -0
  132. package/app/pages/book/[...bookId].vue +47 -0
  133. package/app/pages/group/[...groupId].vue +64 -0
  134. package/app/pages/index.vue +32 -0
  135. package/app/pages/members.vue +7 -0
  136. package/app/pages/practice/[...practice].vue +3 -0
  137. package/app/pages/summary/[...summaryId].vue +3 -0
  138. package/app/public/favicon/article.svg +10 -0
  139. package/app/public/favicon/default.svg +10 -0
  140. package/app/public/favicon/practice.svg +10 -0
  141. package/app/public/favicon/summary.svg +10 -0
  142. package/app/public/logotype.svg +17 -0
  143. package/app/public/og-default.png +0 -0
  144. package/app/public/user.svg +10 -0
  145. package/app/scripts/_immediate.js +4 -0
  146. package/app/scripts/aside/index.ts +59 -0
  147. package/app/scripts/aside/major/nav.ts +26 -0
  148. package/app/scripts/aside/minor/state.ts +37 -0
  149. package/app/scripts/aside/minor/topic.ts +3 -0
  150. package/app/scripts/flag.ts +28 -0
  151. package/app/scripts/og.ts +27 -0
  152. package/app/scripts/preview/build.ts +84 -0
  153. package/app/scripts/preview/data/alert.ts +19 -0
  154. package/app/scripts/preview/data/custom.ts +8 -0
  155. package/app/scripts/preview/data/genericLink.ts +24 -0
  156. package/app/scripts/preview/data/pageLink.ts +20 -0
  157. package/app/scripts/preview/data/unique.ts +70 -0
  158. package/app/scripts/preview/data.ts +26 -0
  159. package/app/scripts/preview/display.ts +39 -0
  160. package/app/scripts/preview/footer.ts +9 -0
  161. package/app/scripts/preview/request.ts +51 -0
  162. package/app/scripts/preview/state.ts +63 -0
  163. package/app/styles/_immediate.css +3 -0
  164. package/app/styles/_util.scss +50 -0
  165. package/app/styles/_utils.scss +44 -0
  166. package/app/styles/app.scss +91 -0
  167. package/app/styles/def/_bp.scss +24 -0
  168. package/app/styles/def/_size.scss +7 -0
  169. package/app/styles/def/_z.scss +5 -0
  170. package/app/styles/default.scss +85 -0
  171. package/app/styles/normalize.scss +63 -0
  172. package/app/styles/partials/_darkMagic.scss +7 -0
  173. package/app/styles/partials/_fnav.scss +18 -0
  174. package/app/styles/partials/_preview.scss +7 -0
  175. package/globalPath.ts +24 -0
  176. package/globals/bitran.ts +39 -0
  177. package/globals/content.ts +22 -0
  178. package/globals/contributor.ts +5 -0
  179. package/globals/erudit.ts +5 -0
  180. package/globals/register.ts +18 -0
  181. package/languages/en.ts +95 -0
  182. package/languages/ru.ts +99 -0
  183. package/module/bitran.ts +34 -0
  184. package/module/config.ts +34 -0
  185. package/module/imports.ts +46 -0
  186. package/module/index.ts +35 -0
  187. package/module/logger.ts +10 -0
  188. package/module/paths.ts +22 -0
  189. package/module/restart.ts +61 -0
  190. package/nuxt.config.ts +96 -0
  191. package/package.json +32 -0
  192. package/server/api/aside/major/nav/bookIds.ts +5 -0
  193. package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -0
  194. package/server/api/aside/major/nav/global.ts +7 -0
  195. package/server/api/aside/minor/news.ts +7 -0
  196. package/server/api/aside/minor/path.ts +78 -0
  197. package/server/api/bitran/content/[location].ts +7 -0
  198. package/server/api/bitran/toc/[location].ts +7 -0
  199. package/server/api/content/data.ts +72 -0
  200. package/server/api/contributor/count.ts +6 -0
  201. package/server/api/fake/content.ts +11 -0
  202. package/server/api/fake/shared/languages.ts +12 -0
  203. package/server/api/language/functions.ts +12 -0
  204. package/server/api/language/phrase/[phraseId].ts +19 -0
  205. package/server/api/language/phraseIds.ts +8 -0
  206. package/server/api/preview/page/[...parts].ts +51 -0
  207. package/server/api/preview/unique/[location].ts +55 -0
  208. package/server/plugin/bitran/content.ts +176 -0
  209. package/server/plugin/bitran/core.ts +51 -0
  210. package/server/plugin/bitran/location.ts +25 -0
  211. package/server/plugin/bitran/products/include.ts +229 -0
  212. package/server/plugin/bitran/products/link.ts +114 -0
  213. package/server/plugin/bitran/setup.ts +10 -0
  214. package/server/plugin/bitran/toc.ts +82 -0
  215. package/server/plugin/build/close.ts +10 -0
  216. package/server/plugin/build/jobs/content/builderArgs.ts +8 -0
  217. package/server/plugin/build/jobs/content/generic.ts +176 -0
  218. package/server/plugin/build/jobs/content/parse.ts +90 -0
  219. package/server/plugin/build/jobs/content/path.ts +6 -0
  220. package/server/plugin/build/jobs/content/type/book.ts +9 -0
  221. package/server/plugin/build/jobs/content/type/group.ts +37 -0
  222. package/server/plugin/build/jobs/content/type/topic.ts +36 -0
  223. package/server/plugin/build/jobs/contributors.ts +66 -0
  224. package/server/plugin/build/jobs/language.ts +36 -0
  225. package/server/plugin/build/jobs/nav.ts +209 -0
  226. package/server/plugin/build/process.ts +25 -0
  227. package/server/plugin/build/rebuild.ts +55 -0
  228. package/server/plugin/build/setup.ts +21 -0
  229. package/server/plugin/content/absoluteId.ts +94 -0
  230. package/server/plugin/content/context.ts +112 -0
  231. package/server/plugin/db/entities/Book.ts +7 -0
  232. package/server/plugin/db/entities/Content.ts +49 -0
  233. package/server/plugin/db/entities/Contribution.ts +10 -0
  234. package/server/plugin/db/entities/Contributor.ts +16 -0
  235. package/server/plugin/db/entities/Group.ts +14 -0
  236. package/server/plugin/db/entities/Hash.ts +15 -0
  237. package/server/plugin/db/entities/Topic.ts +20 -0
  238. package/server/plugin/db/entities/Unique.ts +21 -0
  239. package/server/plugin/db/setup.ts +34 -0
  240. package/server/plugin/global.ts +18 -0
  241. package/server/plugin/importer.ts +12 -0
  242. package/server/plugin/index.ts +9 -0
  243. package/server/plugin/logger.ts +23 -0
  244. package/server/plugin/nav/node.ts +26 -0
  245. package/server/plugin/nav/utils.ts +129 -0
  246. package/server/plugin/repository/book.ts +21 -0
  247. package/server/plugin/repository/content.ts +238 -0
  248. package/server/plugin/repository/contributor.ts +8 -0
  249. package/server/plugin/repository/frontNav.ts +148 -0
  250. package/server/plugin/repository/topic.ts +32 -0
  251. package/server/tsconfig.json +7 -0
  252. package/shared/aside/minor.ts +50 -0
  253. package/shared/asset.ts +15 -0
  254. package/shared/bitran/alias.ts +17 -0
  255. package/shared/bitran/context.ts +7 -0
  256. package/shared/bitran/location.ts +166 -0
  257. package/shared/bitran/products/alias/core/factory.ts +46 -0
  258. package/shared/bitran/products/alias/core/index.ts +13 -0
  259. package/shared/bitran/products/alias/render/Alias.vue +10 -0
  260. package/shared/bitran/products/alias/render/icon.svg +3 -0
  261. package/shared/bitran/products/alias/render/index.ts +17 -0
  262. package/shared/bitran/products/alias/render/languages/en.ts +5 -0
  263. package/shared/bitran/products/alias/render/languages/ru.ts +5 -0
  264. package/shared/bitran/products/alias/shared.ts +11 -0
  265. package/shared/bitran/products/heading/core/factory.ts +53 -0
  266. package/shared/bitran/products/heading/core/index.ts +19 -0
  267. package/shared/bitran/products/heading/render/Heading.vue +47 -0
  268. package/shared/bitran/products/heading/render/icon.svg +3 -0
  269. package/shared/bitran/products/heading/render/index.ts +17 -0
  270. package/shared/bitran/products/heading/render/languages/en.ts +5 -0
  271. package/shared/bitran/products/heading/render/languages/ru.ts +5 -0
  272. package/shared/bitran/products/heading/shared.ts +13 -0
  273. package/shared/bitran/products/include/core/factory.ts +61 -0
  274. package/shared/bitran/products/include/core/index.ts +13 -0
  275. package/shared/bitran/products/include/render/Include.vue +13 -0
  276. package/shared/bitran/products/include/render/icon.svg +3 -0
  277. package/shared/bitran/products/include/render/index.ts +18 -0
  278. package/shared/bitran/products/include/render/languages/en.ts +5 -0
  279. package/shared/bitran/products/include/render/languages/ru.ts +5 -0
  280. package/shared/bitran/products/include/shared.ts +15 -0
  281. package/shared/bitran/products/link/core/factory.ts +20 -0
  282. package/shared/bitran/products/link/core/index.ts +17 -0
  283. package/shared/bitran/products/link/render/Link.vue +174 -0
  284. package/shared/bitran/products/link/render/icon.svg +3 -0
  285. package/shared/bitran/products/link/render/index.ts +17 -0
  286. package/shared/bitran/products/link/render/languages/en.ts +5 -0
  287. package/shared/bitran/products/link/render/languages/ru.ts +5 -0
  288. package/shared/bitran/products/link/shared.ts +15 -0
  289. package/shared/bitran/products/link/target.ts +134 -0
  290. package/shared/bitran/toc.ts +8 -0
  291. package/shared/content/context.ts +9 -0
  292. package/shared/content/data/base.ts +32 -0
  293. package/shared/content/data/index.ts +5 -0
  294. package/shared/content/data/type/book.ts +5 -0
  295. package/shared/content/data/type/group.ts +6 -0
  296. package/shared/content/data/type/topic.ts +11 -0
  297. package/shared/content/previousNext.ts +9 -0
  298. package/shared/contributor.ts +5 -0
  299. package/shared/frontNav.ts +41 -0
  300. package/shared/icons.ts +38 -0
  301. package/shared/image.ts +5 -0
  302. package/shared/link.ts +25 -0
  303. package/shared/types/language.ts +75 -0
  304. package/shared/utils/objectsEqual.ts +4 -0
  305. package/shared/utils/stringColor.ts +9 -0
  306. package/test/bitran/alias.test.ts +44 -0
  307. package/test/bitran/location.test.ts +143 -0
  308. package/test/bitran/products/alias.test.ts +83 -0
  309. package/test/bitran/products/heading.test.ts +119 -0
  310. package/test/bitran/products/include.test.ts +77 -0
  311. package/test/bitran/products/link/factory.test.ts +30 -0
  312. package/test/bitran/products/link/target.test.ts +138 -0
  313. package/tsconfig.json +8 -0
  314. package/utils/stress.ts +9 -0
@@ -0,0 +1,34 @@
1
+ import { addTemplate } from 'nuxt/kit';
2
+ import type { Nuxt } from 'nuxt/schema';
3
+
4
+ import { eruditEndNuxtPath, projectPath } from '@erudit/globalPath';
5
+ import type { EruditBitranConfig } from '@erudit/globals/bitran';
6
+ import { logger } from '@erudit/module/logger';
7
+
8
+ export async function setupBitranConfig(_nuxt: Nuxt) {
9
+ let config: Partial<EruditBitranConfig>;
10
+
11
+ try {
12
+ const projectConfig = (await import(projectPath('bitran'))).default;
13
+ if (!projectConfig) throw new Error('Falsy Bitran config!');
14
+ config = projectConfig;
15
+ } catch (error) {
16
+ logger.warn(`Failed to load Bitran config!\n\n${error}`);
17
+ }
18
+
19
+ const templateFilename = '#erudit/client/bitran.ts';
20
+
21
+ addTemplate({
22
+ filename: templateFilename,
23
+ write: true,
24
+ getContents: () => `
25
+ ${config ? `import bitranConfig from '${projectPath('bitran')}';` : ''}
26
+ export default ${config ? 'bitranConfig' : 'undefined'};
27
+ `,
28
+ });
29
+
30
+ const alias = (_nuxt.options.alias ||= {});
31
+ alias['#erudit/client/bitran'] = eruditEndNuxtPath(
32
+ `.nuxt/${templateFilename}`,
33
+ );
34
+ }
@@ -0,0 +1,34 @@
1
+ import { addTemplate } from 'nuxt/kit';
2
+ import type { Nuxt } from 'nuxt/schema';
3
+ import type { EruditConfig } from 'erudit-cog/schema';
4
+
5
+ import { eruditEndNuxtPath, projectPath } from '@erudit/globalPath';
6
+ import { logger } from '@erudit/module/logger';
7
+
8
+ export async function setupEruditConfig(_nuxt: Nuxt) {
9
+ let config: Partial<EruditConfig> = {};
10
+
11
+ try {
12
+ const projectConfig = (await import(projectPath('erudit'))).default;
13
+ if (!projectConfig) throw new Error('Falsy Erudit config!');
14
+ config = projectConfig;
15
+ } catch (error) {
16
+ logger.warn(`Failed to load Erudit config!\n\n${error}`);
17
+ }
18
+
19
+ const templateFilename = '#erudit/config.ts';
20
+
21
+ addTemplate({
22
+ filename: templateFilename,
23
+ write: true,
24
+ getContents: () => `
25
+ import type { EruditConfig } from 'erudit-cog/schema';
26
+ export default ${JSON.stringify(config, null, ' ')} as Partial<EruditConfig>;
27
+ `,
28
+ });
29
+
30
+ const alias = (_nuxt.options.alias ||= {});
31
+ alias['#erudit/config'] = eruditEndNuxtPath(`.nuxt/${templateFilename}`);
32
+
33
+ return config;
34
+ }
@@ -0,0 +1,46 @@
1
+ import { addImports, addServerImports } from 'nuxt/kit';
2
+
3
+ import { eruditPath } from '@erudit/globalPath';
4
+
5
+ export function setupGlobalImports() {
6
+ addImports([
7
+ {
8
+ name: 'defineEruditConfig',
9
+ from: eruditPath('globals/erudit'),
10
+ },
11
+ {
12
+ name: 'defineContributor',
13
+ from: eruditPath('globals/contributor'),
14
+ },
15
+ {
16
+ name: 'defineBitranConfig',
17
+ from: eruditPath('globals/bitran'),
18
+ },
19
+ // Content
20
+ ...(() => {
21
+ const imports = [
22
+ 'defineBook',
23
+ 'defineGroup',
24
+ 'defineTopic',
25
+ 'defineContentReferences',
26
+ ];
27
+ return imports.map((name) => ({
28
+ name,
29
+ from: eruditPath(`globals/content`),
30
+ }));
31
+ })(),
32
+ // Helper Asset Path Functions
33
+ ...(() => {
34
+ const imports = [
35
+ 'eruditAsset',
36
+ 'contributorAsset',
37
+ 'contentAsset',
38
+ 'publicAsset',
39
+ ];
40
+ return imports.map((name) => ({
41
+ name,
42
+ from: eruditPath(`shared/asset`),
43
+ }));
44
+ })(),
45
+ ]);
46
+ }
@@ -0,0 +1,35 @@
1
+ import { defineNuxtModule, updateTemplates } from 'nuxt/kit';
2
+
3
+ import { registerGlobals } from '@erudit/globals/register';
4
+ import { setupRestartWatcher } from '@erudit/module/restart';
5
+ import { setupEruditConfig } from '@erudit/module/config';
6
+ import { logger } from '@erudit/module/logger';
7
+ import { setupGlobalImports } from '@erudit/module/imports';
8
+ import { setupBitranConfig } from './bitran';
9
+ import { setupGlobalPaths } from './paths';
10
+
11
+ export default defineNuxtModule({
12
+ meta: { name: 'Erudit', configKey: 'erudit' },
13
+ async setup(_options, _nuxt) {
14
+ if (_nuxt.options.dev) setupRestartWatcher(_nuxt);
15
+
16
+ setupGlobalImports();
17
+ registerGlobals();
18
+
19
+ const eruditConfig = await setupEruditConfig(_nuxt);
20
+ await setupBitranConfig(_nuxt);
21
+ setupGlobalPaths(_nuxt);
22
+
23
+ if (eruditConfig.site?.baseUrl) {
24
+ const newBaseUrl = eruditConfig.site.baseUrl;
25
+ _nuxt.options.app.baseURL = newBaseUrl;
26
+ _nuxt.options.nitro.runtimeConfig!.app!.baseURL = newBaseUrl;
27
+ await updateTemplates();
28
+ }
29
+
30
+ // TODO: Watch for contributors folder and create/update template with their IDs
31
+ // TODO: Create such helpers for other features!
32
+
33
+ logger.success('Erudit module setup complete!');
34
+ },
35
+ });
@@ -0,0 +1,10 @@
1
+ import { createConsola } from 'consola';
2
+ import { brandColorTitle } from 'erudit-cog/utils/brand';
3
+
4
+ const tag = brandColorTitle + ' Module';
5
+
6
+ export const logger = createConsola({
7
+ defaults: {
8
+ tag,
9
+ },
10
+ });
@@ -0,0 +1,22 @@
1
+ import { addTemplate } from 'nuxt/kit';
2
+ import type { Nuxt } from 'nuxt/schema';
3
+
4
+ import { ERUDIT_DIR, eruditEndNuxtPath, PROJECT_DIR } from '@erudit/globalPath';
5
+
6
+ export function setupGlobalPaths(_nuxt: Nuxt) {
7
+ const templateFilename = '#erudit/globalPaths.ts';
8
+
9
+ addTemplate({
10
+ filename: templateFilename,
11
+ write: true,
12
+ getContents: () => `
13
+ export const ERUDIT_DIR = '${ERUDIT_DIR}';
14
+ export const PROJECT_DIR = '${PROJECT_DIR}';
15
+ `,
16
+ });
17
+
18
+ const alias = (_nuxt.options.alias ||= {});
19
+ alias['#erudit/globalPaths'] = eruditEndNuxtPath(
20
+ `.nuxt/${templateFilename}`,
21
+ );
22
+ }
@@ -0,0 +1,61 @@
1
+ import { exit } from 'node:process';
2
+ import { globSync } from 'glob';
3
+ import chokidar, { type FSWatcher } from 'chokidar';
4
+ import type { Nuxt } from 'nuxt/schema';
5
+
6
+ import { eruditPath, projectPath } from '@erudit/globalPath';
7
+ import { logger } from '@erudit/module/logger';
8
+ import { stress } from '@erudit/utils/stress';
9
+
10
+ const watchTargets: string[] = [
11
+ // Erudit Nuxt config file
12
+ eruditPath('nuxt.config.ts'),
13
+ // Erudit Globals
14
+ eruditPath('globals'),
15
+ // Erudit Nuxt module non-runtime files
16
+ ...globSync(eruditPath('module/**/*')),
17
+ // Erudit config in project root
18
+ ...globSync(projectPath('erudit.{js,ts}')),
19
+ // Erudit Bitran config in project root
20
+ ...globSync(projectPath('bitran.{js,ts}')),
21
+ ];
22
+
23
+ const ignoreTargets: string[] = [
24
+ // Erudit Nuxt module runtime files
25
+ ...globSync(eruditPath('module/runtime/**/*')),
26
+ ];
27
+
28
+ const restartDelay = 300;
29
+
30
+ //
31
+ //
32
+ //
33
+
34
+ let watcher: FSWatcher;
35
+ let restartTimeout: any;
36
+ let nuxt: Nuxt;
37
+
38
+ export function setupRestartWatcher(_nuxt: Nuxt) {
39
+ nuxt = _nuxt;
40
+
41
+ if (watcher) return;
42
+
43
+ watcher = chokidar.watch(watchTargets, {
44
+ ignored: ignoreTargets,
45
+ ignoreInitial: true,
46
+ });
47
+
48
+ watcher.on('all', (event, path) => {
49
+ clearTimeout(restartTimeout);
50
+ restartTimeout = setTimeout(() => {
51
+ console.log('\n');
52
+ logger.info(
53
+ `Restarting due to critical file change: ${stress(path)}\n\n`,
54
+ );
55
+ // Nuxt Restart Hook won't work when unhandled Node exception is thrown!
56
+ // nuxt.callHook('restart', { hard: true, });
57
+ // So we kill the process and restart it in Erudit CLI instead.
58
+ exit(1337);
59
+ }, restartDelay);
60
+ });
61
+ }
package/nuxt.config.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { eruditPath, projectPath } from './globalPath';
2
+
3
+ export default defineNuxtConfig({
4
+ compatibilityDate: '2025-01-01',
5
+ devtools: { enabled: true },
6
+ future: { compatibilityVersion: 4 },
7
+ ssr: true,
8
+ alias: {
9
+ '@erudit': eruditPath(),
10
+ '@module': eruditPath('module'),
11
+ '@server': eruditPath('server/plugin'),
12
+ '@shared': eruditPath('shared'),
13
+ '@app': eruditPath('app'),
14
+ $: eruditPath('app/styles'),
15
+ },
16
+ modules: [eruditPath('module'), 'nuxt-my-icons'],
17
+ myicons: {
18
+ iconsDir: eruditPath('app/assets/icons'),
19
+ },
20
+ typescript: {
21
+ tsConfig: {
22
+ include: [eruditPath('**/*'), projectPath('**/*')],
23
+ },
24
+ },
25
+ ignore: [
26
+ // Content assets
27
+ ...[
28
+ '**/{book,group,topic}.{js,ts}',
29
+ '**/{article,summary,practice,content}.bi',
30
+ ].map((pattern) => projectPath(`content/${pattern}`)),
31
+ // Contributors assets
32
+ ...['*/contributor.{js,ts}', '*/description.bi'].map((pattern) =>
33
+ projectPath(`contributors/${pattern}`),
34
+ ),
35
+ ],
36
+ nitro: {
37
+ plugins: [eruditPath('server/plugin')],
38
+ prerender: {
39
+ failOnError: false,
40
+ },
41
+ output: {
42
+ publicDir: projectPath('dist'),
43
+ },
44
+ publicAssets: [
45
+ {
46
+ baseURL: '/_erudit-asset/',
47
+ dir: eruditPath('app/public'),
48
+ maxAge: 60 * 60 * 24 * 30,
49
+ },
50
+ {
51
+ baseURL: '/_user-asset/public/',
52
+ dir: projectPath('public'),
53
+ maxAge: 60 * 60 * 24 * 30,
54
+ },
55
+ {
56
+ baseURL: '/_user-asset/content/',
57
+ dir: projectPath('content'),
58
+ maxAge: 60 * 60 * 24 * 30,
59
+ },
60
+ {
61
+ baseURL: '/_user-asset/contributor/',
62
+ dir: projectPath('contributors'),
63
+ maxAge: 60 * 60 * 24 * 30,
64
+ },
65
+ ],
66
+ esbuild: {
67
+ options: {
68
+ tsconfigRaw: {
69
+ compilerOptions: {
70
+ experimentalDecorators: true, // Make TypeORM work with Nuxt
71
+ },
72
+ },
73
+ },
74
+ },
75
+ },
76
+ vite: {
77
+ optimizeDeps: {
78
+ include: [
79
+ '@floating-ui/vue',
80
+ 'bitran',
81
+ 'bitran/core',
82
+ 'bitran/render',
83
+ 'yaml',
84
+ 'slugify',
85
+ ],
86
+ },
87
+ css: {
88
+ preprocessorOptions: {
89
+ scss: {
90
+ api: 'modern-compiler',
91
+ additionalData: `@use '$/utils' as *;`,
92
+ },
93
+ },
94
+ },
95
+ },
96
+ });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "erudit",
3
+ "version": "2.0.0-dev.7",
4
+ "type": "module",
5
+ "description": "🤓 CMS for perfect educational sites.",
6
+ "license": "MIT",
7
+ "main": "./nuxt.config.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/erudit-js/erudit.git",
11
+ "directory": "packages/erudit"
12
+ },
13
+ "dependencies": {
14
+ "@floating-ui/vue": "^1.1.6",
15
+ "bitran": "^3.0.0-dev.3",
16
+ "chalk": "^5.4.1",
17
+ "chokidar": "^4.0.3",
18
+ "consola": "^3.4.0",
19
+ "erudit-cli": "1.0.0-dev.6",
20
+ "erudit-cog": "1.0.0-dev.3",
21
+ "glob": "^11.0.1",
22
+ "image-size": "^1.2.0",
23
+ "nuxt": "3.15.4",
24
+ "nuxt-my-icons": "1.0.2",
25
+ "sass": "^1.84.0",
26
+ "slugify": "^1.6.6",
27
+ "sqlite3": "^5.1.7",
28
+ "typeorm": "^0.3.20",
29
+ "vue": "latest",
30
+ "vue-router": "latest"
31
+ }
32
+ }
@@ -0,0 +1,5 @@
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+
3
+ export default defineEventHandler(() => {
4
+ return Object.keys(ERUDIT_SERVER.NAV_BOOKS || {});
5
+ });
@@ -0,0 +1,20 @@
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+ import { createBookFrontNav } from '@server/repository/frontNav';
3
+
4
+ export default defineEventHandler(async (event) => {
5
+ const bookId = getRouterParam(event, 'bookId');
6
+
7
+ if (
8
+ !bookId ||
9
+ !ERUDIT_SERVER.NAV_BOOKS ||
10
+ !(bookId in ERUDIT_SERVER.NAV_BOOKS)
11
+ )
12
+ throw createError({
13
+ statusCode: 400,
14
+ statusText: `Unknown book id "${bookId}"!`,
15
+ });
16
+
17
+ const bookNode = ERUDIT_SERVER.NAV_BOOKS[bookId]!;
18
+
19
+ return await createBookFrontNav(bookNode);
20
+ });
@@ -0,0 +1,7 @@
1
+ import type { FrontNav } from '@erudit/shared/frontNav';
2
+ import { ERUDIT_SERVER } from '@server/global';
3
+ import { createGlobalFrontNav } from '@server/repository/frontNav';
4
+
5
+ export default defineEventHandler(async () => {
6
+ return (await createGlobalFrontNav(ERUDIT_SERVER.NAV, false)) as FrontNav;
7
+ });
@@ -0,0 +1,7 @@
1
+ import type { AsideMinorNews } from '@shared/aside/minor';
2
+
3
+ export default defineEventHandler(async () => {
4
+ return <AsideMinorNews>{
5
+ type: 'news',
6
+ };
7
+ });
@@ -0,0 +1,78 @@
1
+ import { isTopicPart } from 'erudit-cog/schema';
2
+
3
+ import type { AsideMinorContent, AsideMinorTopic } from '@shared/aside/minor';
4
+ import { getBitranToc } from '@erudit/server/plugin/bitran/toc';
5
+ import {
6
+ getContentContributors,
7
+ getFullContentId,
8
+ getPreviousNext,
9
+ } from '@erudit/server/plugin/repository/content';
10
+ import { getTopicPartsLinks } from '@erudit/server/plugin/repository/topic';
11
+ import { locationFromPath } from '@erudit/shared/bitran/location';
12
+
13
+ export default defineEventHandler(async (event) => {
14
+ const query = getQuery<{ path: string }>(event);
15
+
16
+ if (!query.path)
17
+ throw createError({
18
+ statusCode: 400,
19
+ statusText: 'Missing "path" query parameter!',
20
+ });
21
+
22
+ const path = query.path.substring(1);
23
+ const pathStart = path.split('/')[0];
24
+
25
+ if (isTopicPart(pathStart)) return await createTopicData(path);
26
+
27
+ if (['book', 'group'].includes(pathStart))
28
+ return await createContentData(pathStart, path);
29
+
30
+ return 'news';
31
+ });
32
+
33
+ async function createTopicData(path: string): Promise<AsideMinorTopic> {
34
+ const location = locationFromPath(path);
35
+
36
+ if (!location)
37
+ throw createError({
38
+ statusCode: 400,
39
+ statusText: `Provided path "${path}" is not a valid topic location!`,
40
+ });
41
+
42
+ const contentId = location.path;
43
+ const fullContentId = (await getFullContentId(contentId))!;
44
+
45
+ const toc = await getBitranToc(location);
46
+ const previousNext = await getPreviousNext(contentId);
47
+ const topicPartsLinks = await getTopicPartsLinks(contentId);
48
+ const contributors = await getContentContributors(contentId);
49
+
50
+ return {
51
+ type: 'topic',
52
+ fullContentId,
53
+ location,
54
+ toc,
55
+ nav: {
56
+ ...previousNext,
57
+ ...topicPartsLinks,
58
+ },
59
+ contributors,
60
+ };
61
+ }
62
+
63
+ async function createContentData(
64
+ type: string,
65
+ path: string,
66
+ ): Promise<AsideMinorContent> {
67
+ const contentId = path.split('/').slice(1).join('/');
68
+ const fullContentId = (await getFullContentId(contentId))!;
69
+ const previousNext = await getPreviousNext(contentId);
70
+ const contributors = await getContentContributors(contentId);
71
+
72
+ return {
73
+ type: type as any,
74
+ fullContentId,
75
+ nav: previousNext,
76
+ contributors,
77
+ };
78
+ }
@@ -0,0 +1,7 @@
1
+ import { parseUrlLocation } from '@server/bitran/location';
2
+ import { getBitranContent } from '@server/bitran/content';
3
+
4
+ export default defineEventHandler(async (event) => {
5
+ const location = parseUrlLocation(getRouterParam(event, 'location') || '');
6
+ return await getBitranContent(location);
7
+ });
@@ -0,0 +1,7 @@
1
+ import { parseUrlLocation } from '@server/bitran/location';
2
+ import { getBitranToc } from '@server/bitran/toc';
3
+
4
+ export default defineEventHandler(async (event) => {
5
+ const location = parseUrlLocation(getRouterParam(event, 'location') || '');
6
+ return await getBitranToc(location);
7
+ });
@@ -0,0 +1,72 @@
1
+ import { getTopicPartsLinks } from '@server/repository/topic';
2
+ import { getContentBookFor } from '@server/repository/book';
3
+ import { getContentGenericData } from '@server/repository/content';
4
+
5
+ import type { ContentGenericData } from '@shared/content/data/base';
6
+ import type { ContentTopicData } from '@shared/content/data/type/topic';
7
+ import type { ContentGroupData } from '@shared/content/data/type/group';
8
+ import type { ContentBookData } from '@shared/content/data/type/book';
9
+
10
+ export default defineEventHandler(async (event) => {
11
+ const contentId = getQuery(event)?.contentId as string;
12
+
13
+ if (!contentId)
14
+ throw createError({
15
+ statusCode: 400,
16
+ statusText: 'Missing content ID!',
17
+ });
18
+
19
+ const generic = await getContentGenericData(contentId);
20
+
21
+ switch (generic.type) {
22
+ case 'topic':
23
+ return await getTopicData(generic);
24
+ case 'group':
25
+ return await getGroupData(generic);
26
+ case 'book':
27
+ return await getBookData(generic);
28
+ }
29
+
30
+ throw createError({
31
+ statusCode: 400,
32
+ statusText: `Unknown content data type "${generic.type}"!`,
33
+ });
34
+ });
35
+
36
+ //
37
+ //
38
+ //
39
+
40
+ async function getTopicData(
41
+ generic: ContentGenericData,
42
+ ): Promise<ContentTopicData> {
43
+ const contentBook = await getContentBookFor(generic.contentId);
44
+
45
+ return {
46
+ type: 'topic',
47
+ generic,
48
+ bookTitle: contentBook?.title,
49
+ topicPartLinks: await getTopicPartsLinks(generic.contentId),
50
+ };
51
+ }
52
+
53
+ async function getGroupData(
54
+ generic: ContentGenericData,
55
+ ): Promise<ContentGroupData> {
56
+ const contentBook = await getContentBookFor(generic.contentId);
57
+
58
+ return {
59
+ type: 'group',
60
+ generic,
61
+ bookTitle: contentBook?.title,
62
+ };
63
+ }
64
+
65
+ async function getBookData(
66
+ generic: ContentGenericData,
67
+ ): Promise<ContentBookData> {
68
+ return {
69
+ type: 'book',
70
+ generic,
71
+ };
72
+ }
@@ -0,0 +1,6 @@
1
+ import { DbContributor } from '@server/db/entities/Contributor';
2
+ import { ERUDIT_SERVER } from '@server/global';
3
+
4
+ export default defineEventHandler(async () => {
5
+ return await ERUDIT_SERVER.DB.manager.count(DbContributor);
6
+ });
@@ -0,0 +1,11 @@
1
+ export default defineEventHandler(() => {
2
+ return {
3
+ commit: {
4
+ commit: {
5
+ author: {
6
+ date: '2019-08-30T14:57:06.000Z'
7
+ }
8
+ }
9
+ }
10
+ }
11
+ });
@@ -0,0 +1,12 @@
1
+ export default defineEventHandler(() => {
2
+ return {
3
+ en: {
4
+ name: 'English',
5
+ link: 'https://en.omath.net',
6
+ },
7
+ ru: {
8
+ name: 'Русский',
9
+ link: 'https://omath.ru',
10
+ },
11
+ };
12
+ });
@@ -0,0 +1,12 @@
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+
3
+ export default defineEventHandler(() => {
4
+ const strFunctions: Record<string, string> = {};
5
+
6
+ for (const [key, func] of Object.entries(
7
+ ERUDIT_SERVER.LANGUAGE?.functions || {},
8
+ ))
9
+ strFunctions[key] = 'return ' + func.toString();
10
+
11
+ return strFunctions;
12
+ });
@@ -0,0 +1,19 @@
1
+ import type { EruditPhraseId } from '@shared/types/language';
2
+ import { ERUDIT_SERVER } from '@server/global';
3
+
4
+ export default defineEventHandler((event) => {
5
+ const phraseId = getRouterParam(event, 'phraseId');
6
+ const phrase =
7
+ ERUDIT_SERVER.LANGUAGE?.phrases?.[phraseId as EruditPhraseId];
8
+
9
+ setResponseHeader(event, 'content-type', 'text/plain');
10
+
11
+ if (typeof phrase === 'string') return phrase;
12
+ else if (typeof phrase === 'function')
13
+ return '~!~FUNC~!~' + 'return ' + phrase.toString();
14
+
15
+ throw createError({
16
+ statusCode: 400,
17
+ statusText: `Unknown phrase id "${phraseId}"!`,
18
+ });
19
+ });
@@ -0,0 +1,8 @@
1
+ import { ERUDIT_SERVER } from '@server/global';
2
+ import type { EruditPhraseId } from '@shared/types/language';
3
+
4
+ export default defineEventHandler(() => {
5
+ return Object.keys(
6
+ ERUDIT_SERVER.LANGUAGE?.phrases || [],
7
+ ) as EruditPhraseId[];
8
+ });