erudit 3.0.0-dev.14 → 3.0.0-dev.16

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 (243) hide show
  1. package/app/app.vue +191 -195
  2. package/app/components/Loading.vue +23 -23
  3. package/app/components/SiteAside.vue +393 -393
  4. package/app/components/SiteMain.vue +32 -32
  5. package/app/components/ads/Ads.vue +35 -0
  6. package/app/components/ads/AdsBannerAside.vue +61 -0
  7. package/app/components/ads/AdsBannerBottom.vue +22 -0
  8. package/app/components/ads/AdsProviderCustom.vue +35 -0
  9. package/app/components/ads/AdsProviderYandex.vue +54 -0
  10. package/app/components/ads/AdsReplacer.vue +73 -0
  11. package/app/components/aside/AsideListItem.vue +74 -74
  12. package/app/components/aside/AsideMajor.vue +56 -56
  13. package/app/components/aside/AsideMinor.vue +73 -71
  14. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  15. package/app/components/aside/major/PaneSwitch.vue +54 -54
  16. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  17. package/app/components/aside/major/SiteInfo.vue +85 -85
  18. package/app/components/aside/major/panes/Language.vue +79 -79
  19. package/app/components/aside/major/panes/Pages.vue +34 -34
  20. package/app/components/aside/major/panes/Search.vue +11 -11
  21. package/app/components/aside/major/panes/nav/Nav.vue +92 -92
  22. package/app/components/aside/major/panes/nav/NavBook.vue +95 -95
  23. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  24. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  25. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  26. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  27. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  28. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  29. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  30. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  31. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  32. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  33. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -13
  34. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  35. package/app/components/aside/major/panes/other/Other.vue +16 -16
  36. package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
  37. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  38. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  39. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  40. package/app/components/aside/minor/Contribute.vue +145 -145
  41. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
  42. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
  43. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  44. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  45. package/app/components/aside/minor/topic/TopicToc.vue +214 -214
  46. package/app/components/aside/minor/topic/TopicTocItem.vue +32 -32
  47. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  48. package/app/components/bitran/BitranContent.vue +91 -91
  49. package/app/components/bitran/RenderWrapper.vue +10 -10
  50. package/app/components/contributor/ContributorAvatar.vue +45 -45
  51. package/app/components/contributor/ContributorListItem.vue +35 -35
  52. package/app/components/main/topic/MainTopic.vue +88 -78
  53. package/app/components/main/topic/TopicPartSwitch.vue +118 -118
  54. package/app/components/main/utils/Breadcrumb.vue +74 -70
  55. package/app/components/main/utils/ContentDecoration.vue +29 -29
  56. package/app/components/main/utils/ContentDescription.vue +19 -19
  57. package/app/components/main/utils/ContentPopover.vue +188 -188
  58. package/app/components/main/utils/ContentPopovers.vue +111 -111
  59. package/app/components/main/utils/ContentReferences.vue +70 -70
  60. package/app/components/main/utils/ContentSection.vue +45 -45
  61. package/app/components/main/utils/ContentTitle.vue +63 -63
  62. package/app/components/main/utils/reference/ReferenceGroup.vue +38 -38
  63. package/app/components/main/utils/reference/ReferenceItem.vue +70 -70
  64. package/app/components/main/utils/reference/ReferenceSource.vue +120 -118
  65. package/app/components/preview/Preview.vue +186 -186
  66. package/app/components/preview/PreviewDisplay.vue +139 -139
  67. package/app/components/preview/PreviewFooterAction.vue +73 -73
  68. package/app/components/preview/PreviewLoading.vue +14 -14
  69. package/app/components/preview/PreviewScreen.vue +141 -141
  70. package/app/components/preview/display/Alert.vue +50 -50
  71. package/app/components/preview/display/Custom.vue +18 -18
  72. package/app/components/preview/display/GenericLink.vue +48 -48
  73. package/app/components/preview/display/PageLink.vue +22 -20
  74. package/app/components/preview/display/Unique.vue +55 -55
  75. package/app/components/transition/Fade.vue +19 -19
  76. package/app/components/tree/TreeContainer.vue +11 -11
  77. package/app/components/tree/TreeItem.vue +89 -89
  78. package/app/composables/bitran.ts +108 -108
  79. package/app/composables/bitranContent.ts +92 -92
  80. package/app/composables/bitranLocation.ts +7 -7
  81. package/app/composables/contentData.ts +38 -36
  82. package/app/composables/contentPage.ts +158 -158
  83. package/app/composables/contentRoute.ts +45 -45
  84. package/app/composables/darkMagic.ts +24 -24
  85. package/app/composables/externalApi.ts +69 -63
  86. package/app/composables/favicon.ts +8 -8
  87. package/app/composables/formatText.ts +99 -99
  88. package/app/composables/majorPane.ts +60 -60
  89. package/app/composables/phrases.ts +65 -65
  90. package/app/composables/theme.ts +29 -29
  91. package/app/composables/url.ts +33 -33
  92. package/app/pages/_test/preview.vue +110 -110
  93. package/app/pages/article/[...articleId].vue +3 -3
  94. package/app/pages/book/[...bookId].vue +47 -47
  95. package/app/pages/group/[...groupId].vue +66 -64
  96. package/app/pages/index.vue +32 -32
  97. package/app/pages/members.vue +6 -6
  98. package/app/pages/practice/[...practice].vue +3 -3
  99. package/app/pages/summary/[...summaryId].vue +3 -3
  100. package/app/plugins/analytics.ts +87 -0
  101. package/app/plugins/prerender.server.ts +22 -22
  102. package/app/scripts/_immediate.js +9 -9
  103. package/app/scripts/aside/index.ts +59 -59
  104. package/app/scripts/aside/major/nav.ts +26 -26
  105. package/app/scripts/aside/minor/state.ts +37 -37
  106. package/app/scripts/aside/minor/topic.ts +3 -3
  107. package/app/scripts/flag.ts +28 -28
  108. package/app/scripts/og.ts +27 -27
  109. package/app/scripts/preview/build.ts +76 -76
  110. package/app/scripts/preview/data/alert.ts +19 -19
  111. package/app/scripts/preview/data/custom.ts +8 -8
  112. package/app/scripts/preview/data/genericLink.ts +24 -24
  113. package/app/scripts/preview/data/pageLink.ts +23 -23
  114. package/app/scripts/preview/data/unique.ts +72 -72
  115. package/app/scripts/preview/data.ts +24 -24
  116. package/app/scripts/preview/display.ts +37 -37
  117. package/app/scripts/preview/footer.ts +9 -9
  118. package/app/scripts/preview/request.ts +51 -51
  119. package/app/scripts/preview/state.ts +63 -63
  120. package/app/styles/_immediate.css +7 -7
  121. package/app/styles/_util.scss +43 -43
  122. package/app/styles/_utils.scss +44 -44
  123. package/app/styles/app.scss +91 -91
  124. package/app/styles/def/_bp.scss +27 -27
  125. package/app/styles/def/_size.scss +7 -7
  126. package/app/styles/def/_z.scss +5 -5
  127. package/app/styles/normalize.scss +49 -49
  128. package/app/styles/partials/_darkMagic.scss +5 -5
  129. package/app/styles/partials/_fnav.scss +15 -15
  130. package/app/styles/partials/_preview.scss +5 -5
  131. package/bin/erudit.mjs +2 -2
  132. package/const.ts +4 -4
  133. package/globalPath.ts +21 -21
  134. package/globals/bitran.ts +1 -1
  135. package/globals/content.ts +27 -27
  136. package/globals/contributor.ts +5 -5
  137. package/globals/erudit.ts +5 -5
  138. package/globals/register.ts +18 -18
  139. package/languages/en.ts +94 -94
  140. package/languages/ru.ts +98 -98
  141. package/module/bitran.ts +66 -66
  142. package/module/config.ts +35 -35
  143. package/module/imports.ts +67 -67
  144. package/module/index.ts +47 -49
  145. package/module/logger.ts +10 -10
  146. package/module/paths.ts +22 -22
  147. package/module/restart.ts +61 -61
  148. package/nuxt.config.ts +131 -134
  149. package/package.json +10 -9
  150. package/server/api/aside/major/nav/bookIds.ts +5 -5
  151. package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -20
  152. package/server/api/aside/major/nav/global.ts +7 -7
  153. package/server/api/aside/minor/news.ts +7 -7
  154. package/server/api/aside/minor/path.ts +82 -82
  155. package/server/api/bitran/content/[...location].ts +10 -10
  156. package/server/api/bitran/toc/[...location].ts +9 -9
  157. package/server/api/content/data.ts +75 -75
  158. package/server/api/contributor/count.ts +6 -6
  159. package/server/api/fake/content.ts +11 -11
  160. package/server/api/fake/shared/languages.ts +12 -12
  161. package/server/api/language/functions.ts +12 -12
  162. package/server/api/language/phrase/[phraseId].ts +19 -19
  163. package/server/api/language/phraseIds.ts +8 -8
  164. package/server/api/prerender.ts +120 -120
  165. package/server/api/preview/page/[...parts].ts +78 -78
  166. package/server/api/preview/unique/[...location].ts +61 -61
  167. package/server/api/problem/generator/[...path].ts +26 -0
  168. package/server/plugin/bitran/content.ts +190 -190
  169. package/server/plugin/bitran/elements/include.ts +229 -229
  170. package/server/plugin/bitran/location.ts +39 -39
  171. package/server/plugin/bitran/toc.ts +94 -94
  172. package/server/plugin/bitran/transpiler.ts +18 -18
  173. package/server/plugin/build/close.ts +12 -12
  174. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  175. package/server/plugin/build/jobs/content/generic.ts +191 -191
  176. package/server/plugin/build/jobs/content/parse.ts +113 -113
  177. package/server/plugin/build/jobs/content/path.ts +6 -6
  178. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  179. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  180. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  181. package/server/plugin/build/jobs/contributors.ts +66 -66
  182. package/server/plugin/build/jobs/language.ts +36 -36
  183. package/server/plugin/build/jobs/nav.ts +345 -227
  184. package/server/plugin/build/process.ts +32 -27
  185. package/server/plugin/build/rebuild.ts +66 -66
  186. package/server/plugin/build/setup.ts +19 -19
  187. package/server/plugin/content/context.ts +119 -119
  188. package/server/plugin/db/entities/Book.ts +7 -7
  189. package/server/plugin/db/entities/Content.ts +45 -45
  190. package/server/plugin/db/entities/Contribution.ts +10 -10
  191. package/server/plugin/db/entities/Contributor.ts +16 -16
  192. package/server/plugin/db/entities/File.ts +10 -10
  193. package/server/plugin/db/entities/Group.ts +14 -14
  194. package/server/plugin/db/entities/Hash.ts +15 -15
  195. package/server/plugin/db/entities/Topic.ts +20 -20
  196. package/server/plugin/db/entities/Unique.ts +21 -21
  197. package/server/plugin/db/reset.ts +12 -12
  198. package/server/plugin/db/setup.ts +49 -49
  199. package/server/plugin/global.ts +16 -16
  200. package/server/plugin/importer.ts +16 -16
  201. package/server/plugin/index.ts +9 -9
  202. package/server/plugin/logger.ts +23 -23
  203. package/server/plugin/nav/node.ts +27 -27
  204. package/server/plugin/nav/utils.ts +175 -175
  205. package/server/plugin/repository/book.ts +21 -21
  206. package/server/plugin/repository/content.ts +240 -249
  207. package/server/plugin/repository/contentId.ts +40 -40
  208. package/server/plugin/repository/contributor.ts +8 -8
  209. package/server/plugin/repository/file.ts +10 -10
  210. package/server/plugin/repository/frontNav.ts +145 -145
  211. package/server/plugin/repository/topic.ts +35 -35
  212. package/server/tsconfig.json +9 -9
  213. package/shared/aside/minor.ts +51 -51
  214. package/shared/asset.ts +22 -22
  215. package/shared/bitran/contentId.ts +56 -56
  216. package/shared/bitran/stringContent.ts +6 -6
  217. package/shared/bitran/toc.ts +8 -8
  218. package/shared/content/bookId.ts +12 -12
  219. package/shared/content/context.ts +9 -9
  220. package/shared/content/data/base.ts +32 -32
  221. package/shared/content/data/index.ts +5 -5
  222. package/shared/content/data/type/book.ts +5 -5
  223. package/shared/content/data/type/group.ts +6 -6
  224. package/shared/content/data/type/topic.ts +11 -11
  225. package/shared/content/previousNext.ts +9 -9
  226. package/shared/contributor.ts +5 -5
  227. package/shared/frontNav.ts +41 -41
  228. package/shared/icons.ts +38 -38
  229. package/shared/image.ts +5 -5
  230. package/shared/link.ts +28 -28
  231. package/shared/popover.ts +8 -8
  232. package/shared/types/language.ts +74 -74
  233. package/shared/utils/objectsEqual.ts +4 -4
  234. package/shared/utils/stringColor.ts +9 -9
  235. package/test/contentId.test.ts +91 -91
  236. package/tsconfig.json +8 -8
  237. package/utils/contentPath.ts +67 -67
  238. package/utils/slash.ts +11 -0
  239. package/utils/stress.ts +9 -9
  240. package/app/components/ads/BannerTemplate.vue +0 -51
  241. package/app/components/ads/BottomBanner.vue +0 -45
  242. package/app/components/ads/LeftBanner.vue +0 -50
  243. package/module/problemGenerators.ts +0 -46
@@ -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/slash';
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,158 +1,158 @@
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
- if (contentData.value.type !== 'book') {
71
- const bookTitle = contentData.value?.bookTitle;
72
- title += bookTitle ? ` | ${bookTitle}` : '';
73
- }
74
-
75
- title +=
76
- ' - ' +
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
- .trim()
95
- .replace(/\n/g, ' ');
96
- return;
97
- }
98
-
99
- if (contentRoute.value!.type === 'topic') {
100
- const phraseFunc =
101
- phrase[`seo_${contentRoute.value!.topicPart}_description`];
102
- seo.description.value = phraseFunc(
103
- contentData.value.generic?.seo?.title ||
104
- contentData.value.generic.title!,
105
- );
106
- return;
107
- }
108
-
109
- seo.description.value = '';
110
- })();
111
- };
112
-
113
- useSeoMeta({
114
- // @ts-ignore
115
- title: seo.title,
116
- ogTitle: seo.title,
117
- description: seo.description,
118
- ogDescription: seo.description,
119
- });
120
-
121
- const meta = computed(() => {
122
- return [
123
- ...createOgImageTags(siteUrl, defaultOgImage),
124
- ...(contentData.value.generic?.ogImage
125
- ? createOgImageTags(siteUrl, contentData.value.generic?.ogImage)
126
- : []),
127
- ];
128
- });
129
-
130
- useHead({
131
- meta,
132
- });
133
-
134
- //
135
- //
136
- //
137
-
138
- watchEffect(() => {
139
- setupSeoTitle();
140
- setupSeoDescription();
141
- });
142
-
143
- onMounted(() => {
144
- watchEffect(() => {
145
- contentFavicon();
146
- });
147
- });
148
-
149
- onBeforeUnmount(() => {
150
- favicon.value = defaultFavicon;
151
- });
152
-
153
- //
154
- //
155
- //
156
-
157
- return Promise.all([seoTitlePromise!, seoDescriptionPromise!]);
158
- }
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
+ if (contentData.value.type !== 'book') {
71
+ const bookTitle = contentData.value?.bookTitle;
72
+ title += bookTitle ? ` | ${bookTitle}` : '';
73
+ }
74
+
75
+ title +=
76
+ ' - ' +
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
+ .trim()
95
+ .replace(/\n/g, ' ');
96
+ return;
97
+ }
98
+
99
+ if (contentRoute.value!.type === 'topic') {
100
+ const phraseFunc =
101
+ phrase[`seo_${contentRoute.value!.topicPart}_description`];
102
+ seo.description.value = phraseFunc(
103
+ contentData.value.generic?.seo?.title ||
104
+ contentData.value.generic.title!,
105
+ );
106
+ return;
107
+ }
108
+
109
+ seo.description.value = '';
110
+ })();
111
+ };
112
+
113
+ useSeoMeta({
114
+ // @ts-ignore
115
+ title: seo.title,
116
+ ogTitle: seo.title,
117
+ description: seo.description,
118
+ ogDescription: seo.description,
119
+ });
120
+
121
+ const meta = computed(() => {
122
+ return [
123
+ ...createOgImageTags(siteUrl, defaultOgImage),
124
+ ...(contentData.value.generic?.ogImage
125
+ ? createOgImageTags(siteUrl, contentData.value.generic?.ogImage)
126
+ : []),
127
+ ];
128
+ });
129
+
130
+ useHead({
131
+ meta,
132
+ });
133
+
134
+ //
135
+ //
136
+ //
137
+
138
+ watchEffect(() => {
139
+ setupSeoTitle();
140
+ setupSeoDescription();
141
+ });
142
+
143
+ onMounted(() => {
144
+ watchEffect(() => {
145
+ contentFavicon();
146
+ });
147
+ });
148
+
149
+ onBeforeUnmount(() => {
150
+ favicon.value = defaultFavicon;
151
+ });
152
+
153
+ //
154
+ //
155
+ //
156
+
157
+ return Promise.all([seoTitlePromise!, seoDescriptionPromise!]);
158
+ }
@@ -1,45 +1,45 @@
1
- import type { ContentType, TopicPart } from '@erudit-js/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
- }
1
+ import type { ContentType, TopicPart } from '@erudit-js/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
+ }
@@ -1,24 +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
- }
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
+ }
@@ -1,63 +1,69 @@
1
- import type { EruditConfigDebug } from '@erudit-js/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
- }
1
+ import type { EruditConfigDebug } from '@erudit-js/cog/schema';
2
+
3
+ import eruditConfig from '#erudit/config';
4
+
5
+ let languagesCache: any;
6
+ let repositoryCache: any;
7
+
8
+ function useFakeUrl(
9
+ fakeApiTarget: keyof EruditConfigDebug['fakeApi'],
10
+ ): boolean {
11
+ return eruditConfig.debug?.fakeApi?.[fakeApiTarget] ?? import.meta.dev;
12
+ }
13
+
14
+ function getPayload() {
15
+ const nuxt = useNuxtApp();
16
+ const payloadKey = 'external-api';
17
+ const payload =
18
+ (nuxt.static.data[payloadKey] ||=
19
+ nuxt.payload.data[payloadKey] ||=
20
+ {});
21
+
22
+ return payload;
23
+ }
24
+
25
+ export async function useExternalApiLanguages() {
26
+ const sharedUrl = eruditConfig.repository?.sharedUrl;
27
+ if (!sharedUrl) return {};
28
+
29
+ const payload = getPayload();
30
+ const fake = useFakeUrl('languages');
31
+
32
+ if (fake) {
33
+ payload.languages ||= languagesCache ||= await $fetch(
34
+ '/api/fake/shared/languages',
35
+ );
36
+ } else {
37
+ payload.languages ||= languagesCache ||= await $fetch(
38
+ `https://api.github.com/repos/${sharedUrl}/contents/languages.json`,
39
+ {
40
+ headers: { Accept: 'application/vnd.github.v3.raw' },
41
+ responseType: 'json',
42
+ //transform: (response: string) => JSON.parse(response),
43
+ },
44
+ );
45
+ }
46
+
47
+ return payload.languages;
48
+ }
49
+
50
+ export async function useExternalApiRepository() {
51
+ const repositoryName = eruditConfig.repository?.name;
52
+ const repositoryBranch = eruditConfig.repository?.branch;
53
+
54
+ if (!repositoryName || !repositoryBranch) return undefined;
55
+
56
+ const payload = getPayload();
57
+ const fake = useFakeUrl('repository');
58
+
59
+ if (fake) {
60
+ payload.repository ||= repositoryCache ||=
61
+ await $fetch('/api/fake/content');
62
+ } else {
63
+ payload.repository ||= repositoryCache ||= await $fetch(
64
+ `https://api.github.com/repos/${repositoryName}/branches/${repositoryBranch}`,
65
+ );
66
+ }
67
+
68
+ return payload.repository;
69
+ }