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,22 @@
1
+ <template>
2
+ <Transition name="EruditTransitionFade">
3
+ <slot></slot>
4
+ </Transition>
5
+ </template>
6
+
7
+ <style lang="scss">
8
+ .EruditTransitionFade
9
+ {
10
+ &-enter-active,
11
+ &-leave-active
12
+ {
13
+ transition: opacity var(--transitionSpeed) var(--transitionFunction);
14
+ }
15
+
16
+ &-enter-from,
17
+ &-leave-to
18
+ {
19
+ opacity: 0;
20
+ }
21
+ }
22
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <div :class="$style.treeContainer">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <style lang="scss" module>
8
+ .treeContainer
9
+ {
10
+ padding: calc(var(--gap) / 2) 0;
11
+ }
12
+ </style>
@@ -0,0 +1,89 @@
1
+ <script lang="ts" setup>
2
+ import type { MyIconName } from '#my-icons';
3
+
4
+ defineProps<{
5
+ label: string;
6
+ icon?: MyIconName;
7
+ svg?: string;
8
+ level?: number;
9
+ link?: string;
10
+ active?: boolean;
11
+ accent?: boolean;
12
+ }>();
13
+ </script>
14
+
15
+ <template>
16
+ <NuxtLink
17
+ :prefetch="false"
18
+ :to="link"
19
+ :class="[
20
+ $style.treeItem,
21
+ active && $style.active,
22
+ accent && $style.accent,
23
+ ]"
24
+ :style="{ ['--_level']: level ?? 0 }"
25
+ >
26
+ <MyIcon v-if="icon" :class="$style.icon" :name="icon" />
27
+ <MyRuntimeIcon v-else :class="$style.icon" name="tree-item-icon" :svg />
28
+ <div :class="$style.main">{{ label }}</div>
29
+ <div v-if="$slots.default" :class="$style.after">
30
+ <slot></slot>
31
+ </div>
32
+ </NuxtLink>
33
+ </template>
34
+
35
+ <style lang="scss" module>
36
+ .treeItem {
37
+ display: flex;
38
+ flex-direction: row;
39
+ align-items: center;
40
+ gap: calc(var(--gap) / 1.6);
41
+ padding: calc(var(--gap) / 2) var(--gap);
42
+ padding-left: calc((var(--_level) + 1) * var(--gap));
43
+ font-size: 0.95em;
44
+ color: var(--textMuted);
45
+ text-decoration: none;
46
+ cursor: pointer;
47
+
48
+ @include transition(background);
49
+
50
+ &:hover {
51
+ background: var(--bgAccent);
52
+ .icon,
53
+ .main {
54
+ color: var(--text);
55
+ }
56
+ }
57
+
58
+ &.active {
59
+ .icon,
60
+ .main {
61
+ color: var(--brand);
62
+ }
63
+ }
64
+ &.accent {
65
+ .icon,
66
+ .main {
67
+ color: var(--text);
68
+ }
69
+ }
70
+
71
+ .icon,
72
+ .main {
73
+ @include transition(color);
74
+ }
75
+
76
+ .main {
77
+ flex: 1;
78
+ }
79
+
80
+ .icon,
81
+ .after {
82
+ flex-shrink: 0;
83
+ }
84
+
85
+ .icon {
86
+ font-size: 16px;
87
+ }
88
+ }
89
+ </style>
@@ -0,0 +1,132 @@
1
+ import {
2
+ createBitranCore,
3
+ type GenericProductCore,
4
+ defaultProductCores,
5
+ } from 'bitran/core';
6
+ import {
7
+ createBitranRender,
8
+ createPhrase,
9
+ type ProductRender,
10
+ defaultProductRenders,
11
+ } from 'bitran/render';
12
+
13
+ import eruditConfig from '#erudit/config';
14
+ import bitranConfig from '#erudit/client/bitran';
15
+ import { BitranRenderWrapper } from '#components';
16
+ import type { BitranContext } from '@erudit/shared/bitran/context';
17
+
18
+ // Erudit Bitran Products
19
+ import { headingName } from '@erudit/shared/bitran/products/heading/shared';
20
+ import { heading as headingCore } from '@erudit/shared/bitran/products/heading/core';
21
+ import { heading as headingRender } from '@erudit/shared/bitran/products/heading/render';
22
+ import { aliasName } from '@erudit/shared/bitran/products/alias/shared';
23
+ import { defineAlias as defineAliasCore } from '@erudit/shared/bitran/products/alias/core';
24
+ import { alias as aliasRender } from '@erudit/shared/bitran/products/alias/render';
25
+ import { includeName } from '@erudit/shared/bitran/products/include/shared';
26
+ import { include as includeCore } from '@erudit/shared/bitran/products/include/core';
27
+ import { include as includeRender } from '@erudit/shared/bitran/products/include/render';
28
+ import { linkName } from '@erudit/shared/bitran/products/link/shared';
29
+ import { link as linkCore } from '@erudit/shared/bitran/products/link/core';
30
+ import { link as linkRender } from '@erudit/shared/bitran/products/link/render';
31
+
32
+ export async function useBitran(context: BitranContext) {
33
+ /**
34
+ * TODO:
35
+ * Recreating all products every time make create a significant lag on Bitran content change.
36
+ * Cache products!
37
+ */
38
+
39
+ const formatText = useFormatText();
40
+
41
+ const bitranCore = createBitranCore({
42
+ products: await getProductCores(context),
43
+ });
44
+
45
+ const bitranRender = createBitranRender({
46
+ formatText,
47
+ products: await getProductRenders(),
48
+ RenderWrapper: BitranRenderWrapper,
49
+ });
50
+
51
+ return {
52
+ bitranCore,
53
+ bitranRender,
54
+ };
55
+ }
56
+
57
+ async function getProductCores(context: BitranContext) {
58
+ const projectProductCores: Record<string, GenericProductCore> = {};
59
+
60
+ for (const [name, definition] of Object.entries(
61
+ bitranConfig.products || {},
62
+ )) {
63
+ projectProductCores[name] = await definition.core();
64
+ }
65
+
66
+ const eruditProductCores: Record<string, GenericProductCore> = {
67
+ [aliasName]: defineAliasCore(context),
68
+ [includeName]: includeCore,
69
+ [headingName]: headingCore,
70
+ [linkName]: linkCore,
71
+ };
72
+
73
+ return {
74
+ ...projectProductCores,
75
+ ...eruditProductCores,
76
+ ...defaultProductCores,
77
+ };
78
+ }
79
+
80
+ let productRenders: Record<string, ProductRender>;
81
+
82
+ async function getProductRenders() {
83
+ if (productRenders) return productRenders;
84
+
85
+ const projectProductRenders: Record<string, ProductRender> = {};
86
+
87
+ for (const [name, definition] of Object.entries(
88
+ bitranConfig.products || {},
89
+ )) {
90
+ projectProductRenders[name] = await definition.render();
91
+ }
92
+
93
+ const eruditProductRenders: Record<string, ProductRender> = {
94
+ [aliasName]: aliasRender,
95
+ [includeName]: includeRender,
96
+ [headingName]: headingRender,
97
+ [linkName]: linkRender,
98
+ };
99
+
100
+ productRenders = {
101
+ ...projectProductRenders,
102
+ ...eruditProductRenders,
103
+ ...defaultProductRenders,
104
+ };
105
+
106
+ return productRenders;
107
+ }
108
+
109
+ export async function useBitranProductRender(productName: string) {
110
+ const productRenders = await getProductRenders();
111
+ const productRender = productRenders[productName];
112
+
113
+ if (!productRender)
114
+ throw new Error(`Missing Bitran product render "${productName}"!`);
115
+
116
+ return productRender;
117
+ }
118
+
119
+ export async function useBitranProductIcon(productName: string) {
120
+ const productRender = await useBitranProductRender(productName);
121
+ if (productRender.icon) return await productRender.icon();
122
+ return '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 512 512"><path fill="currentColor" fill-rule="evenodd" d="M448 64v384H64V64zM256 271.085L121.751 405.333h268.497zM106.666 121.751v268.497L240.915 256zm298.667 0L271.085 256l134.248 134.248zm-15.085-15.085H121.751L256 240.915z"/></svg>';
123
+ }
124
+
125
+ export async function useBitranProductLanguage(productName: string) {
126
+ const productRender = await useBitranProductRender(productName);
127
+ return await createPhrase(
128
+ eruditConfig?.language || 'en',
129
+ productRender.languages,
130
+ `erudit:${productName}`,
131
+ );
132
+ }
@@ -0,0 +1,36 @@
1
+ import type { ShallowRef } from 'vue';
2
+ import type { BitranContent } from 'bitran';
3
+ import {
4
+ encodeBitranLocation,
5
+ stringifyBitranLocation,
6
+ type BitranLocation,
7
+ } from '@erudit/shared/bitran/location';
8
+
9
+ export async function useBitranContent(
10
+ location: Ref<BitranLocation | undefined>,
11
+ ) {
12
+ const nuxtApp = useNuxtApp();
13
+ const content = shallowRef<BitranContent>();
14
+
15
+ let contentPromise: Promise<ShallowRef<BitranContent>>;
16
+
17
+ watchEffect(() => {
18
+ if (!location.value) {
19
+ // @ts-ignore
20
+ contentPromise = (() => {
21
+ content.value = undefined;
22
+ return content;
23
+ })();
24
+ }
25
+
26
+ const apiRoute = `/api/bitran/content/${encodeBitranLocation(stringifyBitranLocation(location.value!))}`;
27
+ nuxtApp.runWithContext(() => prerenderRoutes(apiRoute));
28
+ // @ts-ignore
29
+ contentPromise = (async () => {
30
+ content.value = (await $fetch(apiRoute)) as BitranContent;
31
+ return content;
32
+ })();
33
+ });
34
+
35
+ return contentPromise!;
36
+ }
@@ -0,0 +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
+ }
@@ -0,0 +1,36 @@
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
+ }
@@ -0,0 +1,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 (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
+ }
@@ -0,0 +1,45 @@
1
+ import type { ContentType, TopicPart } from 'erudit-cog/schema';
2
+
3
+ interface ContentRouteBase {
4
+ type: ContentType;
5
+ contentId: string;
6
+ }
7
+
8
+ interface TopicRoute extends ContentRouteBase {
9
+ type: 'topic';
10
+ topicPart: TopicPart;
11
+ }
12
+
13
+ interface ContentRoute extends ContentRouteBase {
14
+ type: Exclude<ContentType, 'topic'>;
15
+ }
16
+
17
+ export function useContentRoute(): ComputedRef<
18
+ TopicRoute | ContentRoute | undefined
19
+ > {
20
+ const route = useRoute();
21
+ return computed(() => {
22
+ const match = route.path.match(/\/(.+?)\/(.+)/);
23
+
24
+ if (!match || !match[1] || !match[2]) return undefined;
25
+
26
+ switch (match[1]) {
27
+ case 'article':
28
+ case 'summary':
29
+ case 'practice':
30
+ return <TopicRoute>{
31
+ type: 'topic',
32
+ contentId: match[2],
33
+ topicPart: match[1],
34
+ };
35
+ case 'group':
36
+ case 'book':
37
+ return <ContentRoute>{
38
+ type: match[1],
39
+ contentId: match[2],
40
+ };
41
+ }
42
+
43
+ return undefined;
44
+ });
45
+ }
@@ -0,0 +1,24 @@
1
+ declare let Ya: any;
2
+
3
+ const getElementId = (bannerId: string) => {
4
+ return `DarkMagic_${bannerId}`;
5
+ };
6
+
7
+ const registerBanner = (bannerId: string) => {
8
+ const { binaryTheme } = useTheme();
9
+
10
+ (window['yaContextCb'] ||= []).push(() => {
11
+ Ya.Context.AdvManager.render({
12
+ renderTo: getElementId(bannerId),
13
+ blockId: bannerId,
14
+ darkTheme: binaryTheme.value === 'dark',
15
+ });
16
+ });
17
+ };
18
+
19
+ export function useDarkMagic() {
20
+ return {
21
+ getElementId,
22
+ registerBanner,
23
+ };
24
+ }
@@ -0,0 +1,63 @@
1
+ import type { EruditConfigDebug } from 'erudit-cog/schema';
2
+
3
+ import eruditConfig from '#erudit/config';
4
+
5
+ function useFakeUrl(
6
+ fakeApiTarget: keyof EruditConfigDebug['fakeApi'],
7
+ ): boolean {
8
+ return eruditConfig.debug?.fakeApi?.[fakeApiTarget] ?? import.meta.dev;
9
+ }
10
+
11
+ function getPayload() {
12
+ const nuxt = useNuxtApp();
13
+ const payloadKey = 'external-api';
14
+ const payload =
15
+ (nuxt.static.data[payloadKey] ||=
16
+ nuxt.payload.data[payloadKey] ||=
17
+ {});
18
+
19
+ return payload;
20
+ }
21
+
22
+ export async function useExternalApiLanguages() {
23
+ const sharedUrl = eruditConfig.repository?.sharedUrl;
24
+ if (!sharedUrl) return {};
25
+
26
+ const payload = getPayload();
27
+ const fake = useFakeUrl('languages');
28
+
29
+ if (fake) {
30
+ payload.languages ||= await $fetch('/api/fake/shared/languages');
31
+ } else {
32
+ payload.languages ||= await $fetch(
33
+ `https://api.github.com/repos/${sharedUrl}/contents/languages.json`,
34
+ {
35
+ headers: { Accept: 'application/vnd.github.v3.raw' },
36
+ responseType: 'json',
37
+ //transform: (response: string) => JSON.parse(response),
38
+ },
39
+ );
40
+ }
41
+
42
+ return payload.languages;
43
+ }
44
+
45
+ export async function useExternalApiRepository() {
46
+ const repositoryName = eruditConfig.repository?.name;
47
+ const repositoryBranch = eruditConfig.repository?.branch;
48
+
49
+ if (!repositoryName || !repositoryBranch) return undefined;
50
+
51
+ const payload = getPayload();
52
+ const fake = useFakeUrl('repository');
53
+
54
+ if (fake) {
55
+ payload.repository ||= await $fetch('/api/fake/content');
56
+ } else {
57
+ payload.repository ||= await $fetch(
58
+ `https://api.github.com/repos/${repositoryName}/branches/${repositoryBranch}`,
59
+ );
60
+ }
61
+
62
+ return payload.repository;
63
+ }
@@ -0,0 +1,8 @@
1
+ import eruditConfig from '#erudit/config';
2
+
3
+ export const defaultFavicon =
4
+ eruditConfig.site?.favicon?.default || eruditAsset('favicon/default.svg');
5
+
6
+ export function useFavicon() {
7
+ return useState('favicon', () => defaultFavicon);
8
+ }