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,127 +1,108 @@
1
- import eruditConfig from '#erudit/config';
2
- import bitranConfig from '#erudit/client/bitran';
3
-
4
- import {
5
- createPhraseCaller,
6
- getDefaultRenderers,
7
- getElementIcon,
8
- type ElementVueRenderers,
9
- } from '@bitran-js/renderer-vue';
10
- import {
11
- defineBitranTranspiler,
12
- type BitranTranspiler,
13
- type ElementTranspilers,
14
- } from '@bitran-js/transpiler';
15
- import { aliasesName } from '@erudit-js/bitran-elements/aliases/shared';
16
- import { aliasesTranspiler } from '@erudit-js/bitran-elements/aliases/transpiler';
17
- import { headingName } from '@erudit-js/bitran-elements/heading/shared';
18
- import { headingTranspiler } from '@erudit-js/bitran-elements/heading/transpiler';
19
- import { includeName } from '@erudit-js/bitran-elements/include/shared';
20
- import { includeTranspiler } from '@erudit-js/bitran-elements/include/transpiler';
21
- import { linkName } from '@erudit/shared/bitran/link/shared';
22
- import { linkTranspiler } from '@erudit/shared/bitran/link/transpiler';
23
- import { aliasesRenderer } from '@erudit-js/bitran-elements/aliases/renderer';
24
- import { headingRenderer } from '@erudit-js/bitran-elements/heading/renderer';
25
- import { includeRenderer } from '@erudit-js/bitran-elements/include/renderer';
26
- import { linkRenderer } from '@erudit/shared/bitran/link/renderer';
27
-
28
- let bitranTranspiler!: BitranTranspiler;
29
- let bitranRenderers!: ElementVueRenderers;
30
-
31
- //
32
- // Transpiler
33
- //
34
-
35
- export async function useBitranTranspiler() {
36
- if (bitranTranspiler) return bitranTranspiler;
37
-
38
- const projectTranspilers = await getProjectTranspilers();
39
-
40
- const defaultTranspilers = {
41
- [aliasesName]: aliasesTranspiler,
42
- [includeName]: includeTranspiler,
43
- [headingName]: headingTranspiler,
44
- [linkName]: linkTranspiler,
45
- };
46
-
47
- bitranTranspiler = defineBitranTranspiler({
48
- ...projectTranspilers,
49
- ...defaultTranspilers,
50
- });
51
-
52
- return bitranTranspiler;
53
- }
54
-
55
- async function getProjectTranspilers(): Promise<ElementTranspilers> {
56
- const bitranElements = bitranConfig.elements;
57
-
58
- if (!bitranElements) return {};
59
-
60
- const projectTranspilers: ElementTranspilers = {};
61
- for (const [name, bitranElement] of Object.entries(bitranElements))
62
- projectTranspilers[name] = await bitranElement.transpiler();
63
-
64
- return projectTranspilers;
65
- }
66
-
67
- //
68
- // Renderers
69
- //
70
-
71
- export async function useBitranRenderers() {
72
- if (bitranRenderers) return bitranRenderers;
73
-
74
- const projectRenderers = await getProjectRenderers();
75
-
76
- const defaultRenderers = {
77
- [aliasesName]: aliasesRenderer,
78
- [includeName]: includeRenderer,
79
- [headingName]: headingRenderer,
80
- [linkName]: linkRenderer,
81
- };
82
-
83
- // @ts-ignore
84
- bitranRenderers = {
85
- ...projectRenderers,
86
- ...defaultRenderers,
87
- };
88
-
89
- return bitranRenderers!;
90
- }
91
-
92
- async function getProjectRenderers() {
93
- const bitranElements = bitranConfig.elements;
94
-
95
- if (!bitranElements) return {};
96
-
97
- const projectRenderers: ElementVueRenderers = {};
98
- for (const [name, bitranElement] of Object.entries(bitranElements))
99
- projectRenderers[name] = await bitranElement.renderer();
100
-
101
- return projectRenderers;
102
- }
103
-
104
- //
105
- // Utils
106
- //
107
-
108
- export async function useBitranElementRenderer(productName: string) {
109
- const renderer =
110
- (await useBitranRenderers())[productName] ||
111
- getDefaultRenderers()[productName];
112
-
113
- if (!renderer)
114
- throw new Error(`Missing Bitran product render "${productName}"!`);
115
-
116
- return renderer;
117
- }
118
-
119
- export async function useBitranElementIcon(productName: string) {
120
- const renderer = await useBitranElementRenderer(productName);
121
- return await getElementIcon(renderer);
122
- }
123
-
124
- export async function useBitranElementLanguage(productName: string) {
125
- const renderer = await useBitranElementRenderer(productName);
126
- return await createPhraseCaller(renderer, eruditConfig?.language || 'en');
127
- }
1
+ import {
2
+ createPhraseCaller,
3
+ getDefaultRenderers as getDefaultBitranRenderers,
4
+ getElementIcon,
5
+ type ElementVueRenderers,
6
+ } from '@bitran-js/renderer-vue';
7
+ import {
8
+ defineBitranTranspiler,
9
+ type BitranTranspiler,
10
+ type ElementTranspilers,
11
+ } from '@bitran-js/transpiler';
12
+ import type { EruditBitranElements } from '@erudit-js/cog/schema';
13
+
14
+ import eruditConfig from '#erudit/config';
15
+ import getBitranElements from '#erudit/bitran/app';
16
+
17
+ let elements!: EruditBitranElements;
18
+ let transpilers!: ElementTranspilers;
19
+ let renderers!: ElementVueRenderers;
20
+
21
+ let bitranTranspiler!: BitranTranspiler;
22
+ let bitranRenderers!: ElementVueRenderers;
23
+
24
+ //
25
+ //
26
+ //
27
+
28
+ async function getElements() {
29
+ if (!elements) elements = await getBitranElements();
30
+
31
+ return elements;
32
+ }
33
+
34
+ async function getTranspilers() {
35
+ if (!transpilers) {
36
+ const elements = await getElements();
37
+ transpilers = Object.fromEntries(
38
+ Object.entries(elements).map(([key, item]) => [
39
+ key,
40
+ item.transpiler,
41
+ ]),
42
+ );
43
+ }
44
+ return transpilers;
45
+ }
46
+
47
+ async function getRenderers() {
48
+ if (!renderers) {
49
+ const elements = await getElements();
50
+ renderers = Object.fromEntries(
51
+ Object.entries(elements).map(([key, item]) => [key, item.renderer]),
52
+ );
53
+ }
54
+ return renderers;
55
+ }
56
+
57
+ //
58
+ // Transpiler
59
+ //
60
+
61
+ export async function useBitranTranspiler() {
62
+ if (bitranTranspiler) return bitranTranspiler;
63
+
64
+ bitranTranspiler = defineBitranTranspiler({
65
+ ...(await getTranspilers()),
66
+ });
67
+
68
+ return bitranTranspiler;
69
+ }
70
+
71
+ //
72
+ // Renderers
73
+ //
74
+
75
+ export async function useBitranRenderers() {
76
+ if (bitranRenderers) return bitranRenderers;
77
+
78
+ bitranRenderers = {
79
+ ...(await getRenderers()),
80
+ };
81
+
82
+ return bitranRenderers!;
83
+ }
84
+
85
+ //
86
+ // Utils
87
+ //
88
+
89
+ export async function useBitranElementRenderer(productName: string) {
90
+ const renderer =
91
+ (await getRenderers())[productName] ||
92
+ getDefaultBitranRenderers()[productName];
93
+
94
+ if (!renderer)
95
+ throw new Error(`Missing Bitran product render "${productName}"!`);
96
+
97
+ return renderer;
98
+ }
99
+
100
+ export async function useBitranElementIcon(productName: string) {
101
+ const renderer = await useBitranElementRenderer(productName);
102
+ return await getElementIcon(renderer);
103
+ }
104
+
105
+ export async function useBitranElementLanguage(productName: string) {
106
+ const renderer = await useBitranElementRenderer(productName);
107
+ return await createPhraseCaller(renderer, eruditConfig?.language || 'en');
108
+ }
@@ -1,7 +1,7 @@
1
- import { locationFromPath, type BitranLocation } from '@shared/bitran/location';
2
-
3
- export function useBitranLocation(): ComputedRef<BitranLocation | undefined> {
4
- const route = useRoute();
5
-
6
- return computed(() => locationFromPath(route.path));
7
- }
1
+ import { locationFromPath, type BitranLocation } from '@erudit-js/cog/schema';
2
+
3
+ export function useBitranLocation(): ComputedRef<BitranLocation | undefined> {
4
+ const route = useRoute();
5
+
6
+ return computed(() => locationFromPath(route.path));
7
+ }
@@ -1,36 +1,38 @@
1
- import type { ContentData } from '@shared/content/data';
2
-
3
- export function useContentData<T extends ContentData>() {
4
- const nuxtApp = useNuxtApp();
5
- const contentRoute = useContentRoute();
6
-
7
- const payloadKey = 'content-data';
8
- const payload =
9
- (nuxtApp.static.data[payloadKey] ||=
10
- nuxtApp.payload.data[payloadKey] ||=
11
- {});
12
-
13
- const data = ref<T>();
14
- let promise: Promise<typeof data> | undefined;
15
-
16
- watchEffect(() => {
17
- // @ts-ignore
18
- promise = (async () => {
19
- if (!contentRoute.value) {
20
- data.value = undefined;
21
- return;
22
- }
23
-
24
- const contentId = contentRoute.value.contentId;
25
-
26
- const payloadValue = (payload[contentId] ||= await $fetch(
27
- '/api/content/data',
28
- { query: { contentId } },
29
- ));
30
- data.value = payloadValue as T;
31
- return data;
32
- })();
33
- });
34
-
35
- return promise as any as Promise<Ref<T>>;
36
- }
1
+ import { trailingSlash } from '@erudit/utils/url';
2
+ import type { ContentData } from '@shared/content/data';
3
+
4
+ export function useContentData<T extends ContentData>() {
5
+ const nuxtApp = useNuxtApp();
6
+ const contentRoute = useContentRoute();
7
+
8
+ const payloadKey = 'content-data';
9
+ const payload =
10
+ (nuxtApp.static.data[payloadKey] ||=
11
+ nuxtApp.payload.data[payloadKey] ||=
12
+ {});
13
+
14
+ const data = ref<T>();
15
+ let promise: Promise<typeof data> | undefined;
16
+
17
+ watchEffect(() => {
18
+ // @ts-ignore
19
+ promise = (async () => {
20
+ if (!contentRoute.value) {
21
+ data.value = undefined;
22
+ return;
23
+ }
24
+
25
+ const dataKey = trailingSlash(contentRoute.value.contentId, false);
26
+
27
+ const payloadValue = (payload[dataKey] ||= await $fetch(
28
+ '/api/content/data',
29
+ { query: { contentId: dataKey } },
30
+ ));
31
+
32
+ data.value = payloadValue as T;
33
+ return data;
34
+ })();
35
+ });
36
+
37
+ return promise as any as Promise<Ref<T>>;
38
+ }
@@ -1,156 +1,168 @@
1
- import eruditConfig from '#erudit/config';
2
-
3
- import { createOgImageTags, defaultOgImage } from '@app/scripts/og';
4
- import type { ContentData } from '@shared/content/data';
5
-
6
- export function useContentPage(contentData: Ref<ContentData>) {
7
- const contentRoute = useContentRoute();
8
- const siteUrl = useSiteUrl();
9
- const favicon = useFavicon();
10
-
11
- const phrasePromise = usePhrases(
12
- 'article',
13
- 'summary',
14
- 'practice',
15
- 'site_info_title',
16
- 'seo_article_description',
17
- 'seo_summary_description',
18
- 'seo_practice_description',
19
- );
20
-
21
- //
22
- // Favicon
23
- //
24
-
25
- const contentFavicon = () => {
26
- setTimeout(() => {
27
- const newFavicon = (() => {
28
- switch (contentRoute.value?.type) {
29
- case 'topic':
30
- const topicPart = contentRoute.value.topicPart;
31
- return (
32
- eruditConfig.site?.favicon?.[topicPart] ||
33
- eruditAsset(`favicon/${topicPart}.svg`)
34
- );
35
- }
36
-
37
- return defaultFavicon;
38
- })();
39
-
40
- favicon.value = newFavicon;
41
- }, 500);
42
- };
43
-
44
- //
45
- // SEO
46
- //
47
-
48
- let seoTitlePromise: Promise<void>, seoDescriptionPromise: Promise<void>;
49
-
50
- const seo = {
51
- title: ref<string>(),
52
- description: ref<string>(),
53
- };
54
-
55
- const setupSeoTitle = () => {
56
- seoTitlePromise = (async () => {
57
- const phrase = await phrasePromise;
58
-
59
- let title: string = '';
60
- title +=
61
- contentData.value.generic?.seo?.title ||
62
- contentData.value.generic.title ||
63
- contentData.value.generic.contentId.split('/').pop();
64
-
65
- if (contentData.value.type !== 'book') {
66
- const bookTitle = contentData.value?.bookTitle;
67
- title += bookTitle ? ` | ${bookTitle}` : '';
68
- }
69
-
70
- if (contentRoute.value!.type === 'topic') {
71
- const topicPart = contentRoute.value!.topicPart;
72
-
73
- if (topicPart !== 'article') title += ` | ${phrase[topicPart]}`;
74
- }
75
-
76
- title +=
77
- ' - ' + eruditConfig.seo?.title ||
78
- eruditConfig.site?.title ||
79
- phrase.site_info_title;
80
-
81
- seo.title.value = title;
82
- })();
83
- };
84
-
85
- const setupSeoDescription = () => {
86
- seoDescriptionPromise = (async () => {
87
- const phrase = await phrasePromise;
88
- const customDescription =
89
- contentData.value.generic?.seo?.description ||
90
- contentData.value.generic?.description;
91
-
92
- if (customDescription) {
93
- seo.description.value = customDescription;
94
- return;
95
- }
96
-
97
- if (contentRoute.value!.type === 'topic') {
98
- const phraseFunc =
99
- phrase[`seo_${contentRoute.value!.topicPart}_description`];
100
- seo.description.value = phraseFunc(
101
- contentData.value.generic?.seo?.title ||
102
- contentData.value.generic.title!,
103
- );
104
- return;
105
- }
106
-
107
- seo.description.value = '';
108
- })();
109
- };
110
-
111
- useSeoMeta({
112
- // @ts-ignore
113
- title: seo.title,
114
- ogTitle: seo.title,
115
- description: seo.description,
116
- ogDescription: seo.description,
117
- });
118
-
119
- const meta = computed(() => {
120
- return [
121
- ...createOgImageTags(siteUrl, defaultOgImage),
122
- ...(contentData.value.generic?.ogImage
123
- ? createOgImageTags(siteUrl, contentData.value.generic?.ogImage)
124
- : []),
125
- ];
126
- });
127
-
128
- useHead({
129
- meta,
130
- });
131
-
132
- //
133
- //
134
- //
135
-
136
- watchEffect(() => {
137
- setupSeoTitle();
138
- setupSeoDescription();
139
- });
140
-
141
- onMounted(() => {
142
- watchEffect(() => {
143
- contentFavicon();
144
- });
145
- });
146
-
147
- onBeforeUnmount(() => {
148
- favicon.value = defaultFavicon;
149
- });
150
-
151
- //
152
- //
153
- //
154
-
155
- return Promise.all([seoTitlePromise!, seoDescriptionPromise!]);
156
- }
1
+ import eruditConfig from '#erudit/config';
2
+
3
+ import { createOgImageTags, defaultOgImage } from '@app/scripts/og';
4
+ import type { ContentData } from '@shared/content/data';
5
+
6
+ export function useContentPage(contentData: Ref<ContentData>) {
7
+ const contentRoute = useContentRoute();
8
+ const siteUrl = useSiteUrl();
9
+ const favicon = useFavicon();
10
+
11
+ const phrasePromise = usePhrases(
12
+ 'article',
13
+ 'summary',
14
+ 'practice',
15
+ 'site_info_title',
16
+ 'seo_article_description',
17
+ 'seo_summary_description',
18
+ 'seo_practice_description',
19
+ );
20
+
21
+ //
22
+ // Favicon
23
+ //
24
+
25
+ const contentFavicon = () => {
26
+ setTimeout(() => {
27
+ const newFavicon = (() => {
28
+ switch (contentRoute.value?.type) {
29
+ case 'topic':
30
+ const topicPart = contentRoute.value.topicPart;
31
+ return (
32
+ eruditConfig.site?.favicon?.[topicPart] ||
33
+ eruditAsset(`favicon/${topicPart}.svg`)
34
+ );
35
+ }
36
+
37
+ return defaultFavicon;
38
+ })();
39
+
40
+ favicon.value = newFavicon;
41
+ }, 500);
42
+ };
43
+
44
+ //
45
+ // SEO
46
+ //
47
+
48
+ let seoTitlePromise: Promise<void>, seoDescriptionPromise: Promise<void>;
49
+
50
+ const seo = {
51
+ title: ref<string>(),
52
+ description: ref<string>(),
53
+ };
54
+
55
+ const setupSeoTitle = () => {
56
+ seoTitlePromise = (async () => {
57
+ const phrase = await phrasePromise;
58
+
59
+ let title: string = '';
60
+ title +=
61
+ contentData.value.generic?.seo?.title ||
62
+ contentData.value.generic.title ||
63
+ contentData.value.generic.contentId.split('/').pop();
64
+
65
+ if (contentRoute.value!.type === 'topic') {
66
+ const topicPart = contentRoute.value!.topicPart;
67
+ if (topicPart !== 'article') title += ` | ${phrase[topicPart]}`;
68
+ }
69
+
70
+ // Add book title in the middle section only if not using it as the site title
71
+ if (
72
+ contentData.value.type !== 'book' &&
73
+ contentData.value?.bookTitle &&
74
+ !eruditConfig.content?.bookSiteTitle
75
+ ) {
76
+ title += ` | ${contentData.value.bookTitle}`;
77
+ }
78
+
79
+ // Choose the site title based on configuration
80
+ const siteTitle =
81
+ contentData.value.type !== 'book' &&
82
+ eruditConfig.content?.bookSiteTitle &&
83
+ contentData.value?.bookTitle
84
+ ? contentData.value.bookTitle
85
+ : eruditConfig.seo?.title ||
86
+ eruditConfig.site?.title ||
87
+ phrase.site_info_title;
88
+
89
+ title += ' - ' + siteTitle;
90
+
91
+ seo.title.value = title;
92
+ })();
93
+ };
94
+
95
+ const setupSeoDescription = () => {
96
+ seoDescriptionPromise = (async () => {
97
+ const phrase = await phrasePromise;
98
+ const customDescription =
99
+ contentData.value.generic?.seo?.description ||
100
+ contentData.value.generic?.description;
101
+
102
+ if (customDescription) {
103
+ seo.description.value = customDescription
104
+ .trim()
105
+ .replace(/\n/g, ' ');
106
+ return;
107
+ }
108
+
109
+ if (contentRoute.value!.type === 'topic') {
110
+ const phraseFunc =
111
+ phrase[`seo_${contentRoute.value!.topicPart}_description`];
112
+ seo.description.value = phraseFunc(
113
+ contentData.value.generic?.seo?.title ||
114
+ contentData.value.generic.title!,
115
+ );
116
+ return;
117
+ }
118
+
119
+ seo.description.value = '';
120
+ })();
121
+ };
122
+
123
+ useSeoMeta({
124
+ // @ts-ignore
125
+ title: seo.title,
126
+ ogTitle: seo.title,
127
+ description: seo.description,
128
+ ogDescription: seo.description,
129
+ });
130
+
131
+ const meta = computed(() => {
132
+ return [
133
+ ...createOgImageTags(siteUrl, defaultOgImage),
134
+ ...(contentData.value.generic?.ogImage
135
+ ? createOgImageTags(siteUrl, contentData.value.generic?.ogImage)
136
+ : []),
137
+ ];
138
+ });
139
+
140
+ useHead({
141
+ meta,
142
+ });
143
+
144
+ //
145
+ //
146
+ //
147
+
148
+ watchEffect(() => {
149
+ setupSeoTitle();
150
+ setupSeoDescription();
151
+ });
152
+
153
+ onMounted(() => {
154
+ watchEffect(() => {
155
+ contentFavicon();
156
+ });
157
+ });
158
+
159
+ onBeforeUnmount(() => {
160
+ favicon.value = defaultFavicon;
161
+ });
162
+
163
+ //
164
+ //
165
+ //
166
+
167
+ return Promise.all([seoTitlePromise!, seoDescriptionPromise!]);
168
+ }