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,80 +1,77 @@
1
- type PhraseCaller<T extends EruditPhraseId[]> = {
2
- [K in T[number]]: EruditPhrases[K];
3
- };
4
-
5
- const payloadKey = 'language';
6
-
7
- interface LanguagePayload {
8
- strPhrases: Partial<Record<EruditPhraseId, string>>;
9
- strFunctions: Record<string, string>;
10
- }
11
-
12
- const functions: Record<string, Function> = {};
13
- const functionPhrases: Record<string, Function> = {};
14
-
15
- const phraseApiRoute = (phraseId: EruditPhraseId) =>
16
- `/api/language/phrase/${phraseId}`;
17
- const functionsApiRoute = '/api/language/functions';
18
- const phraseIdsApiRoute = '/api/language/phraseIds';
19
-
20
- export function usePhrases<T extends EruditPhraseId[]>(
21
- ...phraseIds: T
22
- ): Promise<PhraseCaller<T>> {
23
- const nuxt = useNuxtApp();
24
- const payload: LanguagePayload =
25
- (nuxt.static.data[payloadKey] ||=
26
- nuxt.payload.data[payloadKey] ||=
27
- {});
28
-
29
- const prerenderAllPromise = prerenderAllPhrases();
30
- const prepareFunctionsPromise = prepareFunctions(payload);
31
-
32
- return (async () => {
33
- await prerenderAllPromise;
34
- await prepareFunctionsPromise;
35
-
36
- payload.strPhrases ||= {};
37
- const phraseCaller: any = {};
38
-
39
- for (const phraseId of phraseIds) {
40
- const apiRoute = phraseApiRoute(phraseId);
41
- const strPhrase = (payload.strPhrases[phraseId] ||= (await $fetch(
42
- apiRoute,
43
- )) as string);
44
-
45
- if (strPhrase.startsWith('~!~FUNC~!~')) {
46
- const strFunction = strPhrase.replace('~!~FUNC~!~', '');
47
- functionPhrases[phraseId] ||= new Function(strFunction).bind(
48
- functions,
49
- )();
50
- phraseCaller[phraseId] = functionPhrases[phraseId];
51
- } else {
52
- phraseCaller[phraseId] = strPhrase;
53
- }
54
- }
55
-
56
- return phraseCaller as PhraseCaller<T>;
57
- })();
58
- }
59
-
60
- async function prerenderAllPhrases() {
61
- if (import.meta.dev) return;
62
-
63
- if (import.meta.client) return;
64
-
65
- const nuxt = useNuxtApp();
66
-
67
- const phraseIds = await $fetch(phraseIdsApiRoute);
68
- nuxt.runWithContext(() =>
69
- prerenderRoutes(phraseIds.map((phraseId) => phraseApiRoute(phraseId))),
70
- );
71
- }
72
-
73
- async function prepareFunctions(payload: LanguagePayload) {
74
- if (payload?.strFunctions) return;
75
-
76
- payload.strFunctions = await $fetch(functionsApiRoute);
77
-
78
- for (const [funcName, strFunc] of Object.entries(payload.strFunctions))
79
- functions[funcName] = new Function(strFunc)();
80
- }
1
+ type PhraseCaller<T extends EruditPhraseId[]> = {
2
+ [K in T[number]]: EruditPhrases[K];
3
+ };
4
+
5
+ const payloadKey = 'language';
6
+
7
+ interface LanguagePayload {
8
+ strPhrases: Partial<Record<EruditPhraseId, string>>;
9
+ strFunctions: Record<string, string>;
10
+ }
11
+
12
+ let functions: Record<string, Function>;
13
+ const functionPhrases: Record<string, Function> = {};
14
+
15
+ const phraseApiRoute = (phraseId: EruditPhraseId) =>
16
+ `/api/language/phrase/${phraseId}`;
17
+ const functionsApiRoute = '/api/language/functions';
18
+
19
+ export function usePhrases<T extends EruditPhraseId[]>(
20
+ ...phraseIds: T
21
+ ): Promise<PhraseCaller<T>> {
22
+ const nuxt = useNuxtApp();
23
+ const payload: LanguagePayload =
24
+ (nuxt.static.data[payloadKey] ||=
25
+ nuxt.payload.data[payloadKey] ||=
26
+ {});
27
+
28
+ const prepareFunctionsPromise = prepareFunctions(payload);
29
+
30
+ return (async () => {
31
+ await prepareFunctionsPromise;
32
+
33
+ payload.strPhrases ||= {};
34
+ const phraseCaller: any = {};
35
+
36
+ for (const phraseId of phraseIds) {
37
+ const apiRoute = phraseApiRoute(phraseId);
38
+ const strPhrase = (payload.strPhrases[phraseId] ||= (await $fetch(
39
+ apiRoute,
40
+ { responseType: 'text' },
41
+ )) as string);
42
+
43
+ if (strPhrase.startsWith('~!~FUNC~!~')) {
44
+ const strFunction = strPhrase.replace('~!~FUNC~!~', '');
45
+ functionPhrases[phraseId] ||= new Function(
46
+ 'funcs',
47
+ `
48
+ with(funcs) {
49
+ ${strFunction}
50
+ }
51
+ `,
52
+ )(functions);
53
+ phraseCaller[phraseId] = functionPhrases[phraseId];
54
+ } else {
55
+ phraseCaller[phraseId] = strPhrase;
56
+ }
57
+ }
58
+
59
+ return phraseCaller as PhraseCaller<T>;
60
+ })();
61
+ }
62
+
63
+ async function prepareFunctions(payload: LanguagePayload) {
64
+ payload.strFunctions ||= await $fetch(functionsApiRoute, {
65
+ responseType: 'json',
66
+ });
67
+
68
+ functions ||= (() => {
69
+ const _functions: Record<string, Function> = {};
70
+ for (const [funcName, strFunc] of Object.entries(
71
+ payload.strFunctions,
72
+ )) {
73
+ _functions[funcName] = new Function(strFunc)();
74
+ }
75
+ return _functions;
76
+ })();
77
+ }
@@ -1,29 +1,29 @@
1
- const themes = ['auto', 'light', 'dark'] as const;
2
-
3
- export type Theme = (typeof themes)[number];
4
- export type BinaryTheme = 'light' | 'dark';
5
-
6
- export function useTheme() {
7
- const theme = useState<Theme>('theme', () => {
8
- return localStorage.getItem('theme') ?? ('auto' as any);
9
- });
10
-
11
- const binaryTheme = computed(() => {
12
- return theme.value === 'auto'
13
- ? window.matchMedia('(prefers-color-scheme: dark)').matches
14
- ? 'dark'
15
- : 'light'
16
- : theme.value;
17
- });
18
-
19
- const cycle = () => {
20
- theme.value =
21
- themes[(themes.indexOf(theme.value) + 1) % themes.length]!;
22
- };
23
-
24
- return {
25
- theme,
26
- binaryTheme,
27
- cycle,
28
- };
29
- }
1
+ const themes = ['auto', 'light', 'dark'] as const;
2
+
3
+ export type Theme = (typeof themes)[number];
4
+ export type BinaryTheme = 'light' | 'dark';
5
+
6
+ export function useTheme() {
7
+ const theme = useState<Theme>('theme', () => {
8
+ return localStorage.getItem('theme') ?? ('auto' as any);
9
+ });
10
+
11
+ const binaryTheme = computed(() => {
12
+ return theme.value === 'auto'
13
+ ? window.matchMedia('(prefers-color-scheme: dark)').matches
14
+ ? 'dark'
15
+ : 'light'
16
+ : theme.value;
17
+ });
18
+
19
+ const cycle = () => {
20
+ theme.value =
21
+ themes[(themes.indexOf(theme.value) + 1) % themes.length]!;
22
+ };
23
+
24
+ return {
25
+ theme,
26
+ binaryTheme,
27
+ cycle,
28
+ };
29
+ }
@@ -1,33 +1,43 @@
1
- import eruditConfig from '#erudit/config';
2
-
3
- export function useBaseUrlPath() {
4
- const runtimeConfig = useRuntimeConfig();
5
- return (path: string) => {
6
- const baseURL = runtimeConfig.app.baseURL;
7
- if (path.startsWith(baseURL)) return path;
8
- else if (path.startsWith('/')) return baseURL + path.substring(1);
9
- else return path;
10
- };
11
- }
12
-
13
- export function useSiteUrl() {
14
- const runtimeConfig = useRuntimeConfig();
15
- const baseUrl = runtimeConfig.app.baseURL;
16
- const url = useRequestURL();
17
-
18
- if (!import.meta.dev && eruditConfig.site?.buildUrl)
19
- return eruditConfig.site.buildUrl + baseUrl.slice(0, -1);
20
-
21
- return url.origin;
22
- }
23
-
24
- export function usePageUrl() {
25
- const siteUrl = useSiteUrl();
26
- const route = useRoute();
27
-
28
- return computed(() => {
29
- if (route.path === '/') return siteUrl;
30
-
31
- return siteUrl + route.path;
32
- });
33
- }
1
+ import eruditConfig from '#erudit/config';
2
+ import { trailingSlash, normalizeUrl } from '@erudit/utils/url';
3
+
4
+ export function useBaseUrlPath() {
5
+ const runtimeConfig = useRuntimeConfig();
6
+ const baseURL = runtimeConfig.app.baseURL;
7
+
8
+ return (path: string) => {
9
+ const normalizedPath = normalizeUrl(path);
10
+
11
+ if (normalizedPath.startsWith(baseURL)) {
12
+ return normalizedPath;
13
+ }
14
+
15
+ if (normalizedPath.startsWith('/')) {
16
+ return normalizeUrl(baseURL + normalizedPath.substring(1));
17
+ }
18
+
19
+ return normalizedPath;
20
+ };
21
+ }
22
+
23
+ export function useSiteUrl() {
24
+ const runtimeConfig = useRuntimeConfig();
25
+ const baseUrl = runtimeConfig.app.baseURL;
26
+ const url = useRequestURL();
27
+
28
+ if (!import.meta.dev && eruditConfig.site?.buildUrl)
29
+ return eruditConfig.site.buildUrl + baseUrl.slice(0, -1);
30
+
31
+ return normalizeUrl(trailingSlash(url.origin, true));
32
+ }
33
+
34
+ export function usePageUrl() {
35
+ const siteUrl = useSiteUrl();
36
+ const route = useRoute();
37
+
38
+ return computed(() => {
39
+ if (route.path === '/') return siteUrl;
40
+ const fullUrl = siteUrl + route.path;
41
+ return normalizeUrl(trailingSlash(fullUrl, true));
42
+ });
43
+ }
@@ -1,110 +1,110 @@
1
- <script lang="ts" setup>
2
- import { PreviewDataType } from '@app/scripts/preview/data';
3
- import { createPreviewError } from '@app/scripts/preview/data/alert';
4
- import { PreviewRequestType } from '@app/scripts/preview/request';
5
- import {
6
- PreviewThemeName,
7
- showPreview,
8
- togglePreview,
9
- } from '@app/scripts/preview/state';
10
-
11
- function showCustom() {
12
- showPreview({
13
- type: PreviewRequestType.Data,
14
- data: {
15
- type: PreviewDataType.Custom,
16
- message: 'This is custom message for preview!',
17
- footer: {
18
- //iconName: 'arrow-left',
19
- iconSvg:
20
- '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M6.42436 0H9.57565L14.995 16H11.8276L10.8115 13H5.18855L4.17242 16H1.005L6.42436 0ZM6.20468 10H9.79533L8 4.69952L6.20468 10Z"></path> </g></svg>',
21
- secondary: 'Secondary raw text',
22
- primary: 'Primary raw text',
23
- href: 'https://google.com',
24
- },
25
- },
26
- });
27
- }
28
-
29
- function showAlert(theme: PreviewThemeName) {
30
- showPreview({
31
- type: PreviewRequestType.Data,
32
- data: createPreviewError({
33
- theme,
34
- message: 'This is message!',
35
- title: 'Custom Title',
36
- pre: JSON.stringify(
37
- {
38
- foo: 1337,
39
- bar: 'Some text',
40
- },
41
- null,
42
- 4,
43
- ),
44
- }),
45
- });
46
- }
47
- </script>
48
-
49
- <template>
50
- <button @click="() => togglePreview()">Toggle Preview</button>
51
- <div>
52
- Show:
53
- <br />
54
- <button :class="$style.button" @click="showCustom">Custom</button>
55
- <br />
56
- <button
57
- :class="$style.button"
58
- v-for="theme in PreviewThemeName"
59
- @click="() => showAlert(theme)"
60
- >
61
- Alert {{ theme }}
62
- </button>
63
- <br />
64
- <button
65
- :class="$style.button"
66
- @click="
67
- showPreview({
68
- type: PreviewRequestType.MissingElement,
69
- elementId: 'foo-id',
70
- })
71
- "
72
- >
73
- Missing element
74
- </button>
75
- <button
76
- :class="$style.button"
77
- @click="
78
- showPreview({
79
- type: PreviewRequestType.MissingElement,
80
- elementId: 'foo-id',
81
- hashMismatch: { current: 'bar', expected: 'baz' },
82
- })
83
- "
84
- >
85
- Missing element + hash mismatch
86
- </button>
87
- <br />
88
- <button
89
- :class="$style.button"
90
- @click="
91
- showPreview({
92
- type: PreviewRequestType.HashMismatch,
93
- currentHash: 'foo',
94
- expectedHash: 'bar',
95
- })
96
- "
97
- >
98
- Hash mismatch
99
- </button>
100
- </div>
101
- </template>
102
-
103
- <style lang="scss" module>
104
- .button {
105
- border: 2px solid var(--border);
106
- border-radius: 3px;
107
- padding: 3px;
108
- margin: 3px;
109
- }
110
- </style>
1
+ <script lang="ts" setup>
2
+ import { PreviewDataType } from '@app/scripts/preview/data';
3
+ import { createPreviewError } from '@app/scripts/preview/data/alert';
4
+ import { PreviewRequestType } from '@app/scripts/preview/request';
5
+ import {
6
+ PreviewThemeName,
7
+ showPreview,
8
+ togglePreview,
9
+ } from '@app/scripts/preview/state';
10
+
11
+ function showCustom() {
12
+ showPreview({
13
+ type: PreviewRequestType.Data,
14
+ data: {
15
+ type: PreviewDataType.Custom,
16
+ message: 'This is custom message for preview!',
17
+ footer: {
18
+ //iconName: 'arrow-left',
19
+ iconSvg:
20
+ '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M6.42436 0H9.57565L14.995 16H11.8276L10.8115 13H5.18855L4.17242 16H1.005L6.42436 0ZM6.20468 10H9.79533L8 4.69952L6.20468 10Z"></path> </g></svg>',
21
+ secondary: 'Secondary raw text',
22
+ primary: 'Primary raw text',
23
+ href: 'https://google.com',
24
+ },
25
+ },
26
+ });
27
+ }
28
+
29
+ function showAlert(theme: PreviewThemeName) {
30
+ showPreview({
31
+ type: PreviewRequestType.Data,
32
+ data: createPreviewError({
33
+ theme,
34
+ message: 'This is message!',
35
+ title: 'Custom Title',
36
+ pre: JSON.stringify(
37
+ {
38
+ foo: 1337,
39
+ bar: 'Some text',
40
+ },
41
+ null,
42
+ 4,
43
+ ),
44
+ }),
45
+ });
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <button @click="() => togglePreview()">Toggle Preview</button>
51
+ <div>
52
+ Show:
53
+ <br />
54
+ <button :class="$style.button" @click="showCustom">Custom</button>
55
+ <br />
56
+ <button
57
+ :class="$style.button"
58
+ v-for="theme in PreviewThemeName"
59
+ @click="() => showAlert(theme)"
60
+ >
61
+ Alert {{ theme }}
62
+ </button>
63
+ <br />
64
+ <button
65
+ :class="$style.button"
66
+ @click="
67
+ showPreview({
68
+ type: PreviewRequestType.MissingElement,
69
+ elementId: 'foo-id',
70
+ })
71
+ "
72
+ >
73
+ Missing element
74
+ </button>
75
+ <button
76
+ :class="$style.button"
77
+ @click="
78
+ showPreview({
79
+ type: PreviewRequestType.MissingElement,
80
+ elementId: 'foo-id',
81
+ hashMismatch: { current: 'bar', expected: 'baz' },
82
+ })
83
+ "
84
+ >
85
+ Missing element + hash mismatch
86
+ </button>
87
+ <br />
88
+ <button
89
+ :class="$style.button"
90
+ @click="
91
+ showPreview({
92
+ type: PreviewRequestType.HashMismatch,
93
+ currentHash: 'foo',
94
+ expectedHash: 'bar',
95
+ })
96
+ "
97
+ >
98
+ Hash mismatch
99
+ </button>
100
+ </div>
101
+ </template>
102
+
103
+ <style lang="scss" module>
104
+ .button {
105
+ border: 2px solid var(--border);
106
+ border-radius: 3px;
107
+ padding: 3px;
108
+ margin: 3px;
109
+ }
110
+ </style>
@@ -1,3 +1,3 @@
1
- <template>
2
- <MainTopic />
3
- </template>
1
+ <template>
2
+ <MainTopic />
3
+ </template>
@@ -1,47 +1,42 @@
1
- <script lang="ts" setup>
2
- import type { ContentBookData } from '@erudit/shared/content/data/type/book';
3
- import type { MyIconName } from '#my-icons';
4
-
5
- import ContentDecoration from '@app/components/main/utils/ContentDecoration.vue';
6
- import Breadcrumb from '@app/components/main/utils/Breadcrumb.vue';
7
- import ContentTitle from '@app/components/main/utils/ContentTitle.vue';
8
- import ContentDescription from '@app/components/main/utils/ContentDescription.vue';
9
- import ContentPopovers from '@app/components/main/utils/ContentPopovers.vue';
10
-
11
- const bookData = await useContentData<ContentBookData>();
12
- await useContentPage(bookData);
13
-
14
- const phrase = await usePhrases('book');
15
- </script>
16
-
17
- <template>
18
- <ContentDecoration
19
- v-if="bookData.generic.decoration"
20
- :decoration="bookData.generic.decoration"
21
- />
22
-
23
- <Breadcrumb
24
- v-if="bookData.generic.context?.length > 1"
25
- :context="bookData.generic.context"
26
- />
27
-
28
- <ContentTitle
29
- :title="
30
- bookData.generic?.title ||
31
- bookData.generic.contentId.split('/').pop()!
32
- "
33
- :icon="<MyIconName>'outline/book'"
34
- :hint="phrase.book"
35
- />
36
-
37
- <ContentDescription
38
- v-if="bookData.generic?.description"
39
- :description="bookData.generic?.description"
40
- />
41
-
42
- <ContentPopovers :generic="bookData.generic" />
43
-
44
- <!-- Counters, fancy "GO LEARN" button and etc. -->
45
-
46
- <div style="clear: both"></div>
47
- </template>
1
+ <script lang="ts" setup>
2
+ import type { ContentBookData } from '@erudit/shared/content/data/type/book';
3
+ import type { MyIconName } from '#my-icons';
4
+
5
+ import ContentBreadcrumb from '@app/components/main/content/ContentBreadcrumb.vue';
6
+ import ContentDecoration from '@app/components/main/content/ContentDecoration.vue';
7
+ import ContentPopovers from '@app/components/main/content/ContentPopovers.vue';
8
+
9
+ const bookData = await useContentData<ContentBookData>();
10
+ await useContentPage(bookData);
11
+
12
+ const phrase = await usePhrases('book');
13
+ </script>
14
+
15
+ <template>
16
+ <ContentDecoration
17
+ v-if="bookData.generic.decoration"
18
+ :decoration="bookData.generic.decoration"
19
+ />
20
+
21
+ <ContentBreadcrumb :context="bookData.generic.context" />
22
+
23
+ <MainTitle
24
+ :title="
25
+ bookData.generic?.title ||
26
+ bookData.generic.contentId.split('/').pop()!
27
+ "
28
+ :icon="<MyIconName>'outline/book'"
29
+ :hint="phrase.book"
30
+ />
31
+
32
+ <MainDescription
33
+ v-if="bookData.generic?.description"
34
+ :description="bookData.generic?.description"
35
+ />
36
+
37
+ <ContentPopovers :generic="bookData.generic" />
38
+
39
+ <!-- Counters, fancy "GO LEARN" button and etc. -->
40
+
41
+ <div style="clear: both"></div>
42
+ </template>