erudit 4.0.0-dev.4 → 4.0.0-dev.5

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 (336) hide show
  1. package/.nuxtrc +1 -1
  2. package/app/app.vue +34 -34
  3. package/app/components/EruditLink.ts +7 -7
  4. package/app/components/FancyBold.vue +16 -16
  5. package/app/components/FancyCard.vue +52 -58
  6. package/app/components/FancyCardTag.vue +16 -16
  7. package/app/components/Loading.vue +7 -7
  8. package/app/components/Prose.vue +55 -52
  9. package/app/components/ScrollHolder.vue +13 -13
  10. package/app/components/SmartMedia.vue +107 -112
  11. package/app/components/ads/Ads.vue +17 -17
  12. package/app/components/ads/AdsBannerAside.vue +29 -29
  13. package/app/components/ads/AdsBannerBottom.vue +6 -6
  14. package/app/components/ads/AdsReplacer.vue +19 -21
  15. package/app/components/ads/provider/Custom.vue +9 -9
  16. package/app/components/ads/provider/Yandex.vue +56 -56
  17. package/app/components/aside/AsideListItem.vue +47 -52
  18. package/app/components/aside/AsideMajor.vue +6 -6
  19. package/app/components/aside/AsideMinor.vue +47 -52
  20. package/app/components/aside/AsidePlainMessage.vue +9 -9
  21. package/app/components/aside/AsideSwitch.vue +53 -54
  22. package/app/components/aside/major/PaneHolder.vue +61 -61
  23. package/app/components/aside/major/PaneSwitcher.vue +50 -55
  24. package/app/components/aside/major/PaneSwitcherButton.vue +24 -24
  25. package/app/components/aside/major/PaneTemplate.vue +3 -3
  26. package/app/components/aside/major/SiteInfo.vue +40 -42
  27. package/app/components/aside/major/contentNav/PaneBookNav.vue +107 -116
  28. package/app/components/aside/major/contentNav/PaneGlobalNav.vue +19 -19
  29. package/app/components/aside/major/contentNav/items/ContentNavBook.vue +8 -8
  30. package/app/components/aside/major/contentNav/items/ContentNavFolder.vue +55 -56
  31. package/app/components/aside/major/contentNav/items/ContentNavItem.vue +16 -16
  32. package/app/components/aside/major/contentNav/items/ContentNavPage.vue +2 -6
  33. package/app/components/aside/major/contentNav/items/ContentNavSeparator.vue +34 -35
  34. package/app/components/aside/major/contentNav/items/ContentNavTopic.vue +6 -6
  35. package/app/components/aside/major/contentNav/items/Flags.vue +31 -33
  36. package/app/components/aside/major/contentNav/items/ItemTemplate.vue +13 -13
  37. package/app/components/aside/major/languages/PaneLanguages.vue +40 -40
  38. package/app/components/aside/major/pages/PanePages.vue +45 -45
  39. package/app/components/aside/major/search/PaneSearch.vue +109 -100
  40. package/app/components/aside/major/search/SearchInput.vue +52 -53
  41. package/app/components/aside/major/search/SearchResult.vue +123 -75
  42. package/app/components/aside/major/search/SearchStatus.vue +28 -28
  43. package/app/components/aside/major/search/search.worker.ts +129 -129
  44. package/app/components/aside/major/settings/BuildTime.vue +15 -15
  45. package/app/components/aside/major/settings/EngineVersion.vue +8 -7
  46. package/app/components/aside/major/settings/PaneSettings.vue +8 -8
  47. package/app/components/aside/major/settings/ThemeSwitcher.vue +36 -36
  48. package/app/components/aside/major/settings/repository/Repository.vue +18 -18
  49. package/app/components/aside/major/settings/repository/SecondaryGitHub.vue +47 -47
  50. package/app/components/aside/minor/AsideMinorPane.vue +5 -5
  51. package/app/components/aside/minor/AsideMinorPlainHeader.vue +20 -20
  52. package/app/components/aside/minor/content/AsideMinorContentContributions.vue +47 -51
  53. package/app/components/aside/minor/content/AsideMinorContentPage.vue +37 -37
  54. package/app/components/aside/minor/content/AsideMinorContentTopic.vue +61 -66
  55. package/app/components/aside/minor/content/ButtonPaneContributions.vue +101 -114
  56. package/app/components/aside/minor/content/ButtonPaneImprove.vue +112 -123
  57. package/app/components/aside/minor/content/Contribution.vue +36 -36
  58. package/app/components/aside/minor/content/Toc.vue +163 -163
  59. package/app/components/aside/minor/content/TocItem.vue +91 -91
  60. package/app/components/aside/minor/content/TopicPartButton.vue +35 -35
  61. package/app/components/aside/minor/contributor/AsideMinorContributor.vue +36 -39
  62. package/app/components/aside/minor/contributor/ItemBook.vue +33 -39
  63. package/app/components/aside/minor/contributor/ItemContent.vue +17 -17
  64. package/app/components/aside/minor/news/AsideMinorNews.vue +132 -132
  65. package/app/components/aside/minor/news/NewsItem.vue +69 -69
  66. package/app/components/aside/minor/news/RenderNewsElement.vue +42 -42
  67. package/app/components/aside/minor/news/elements/Mix.vue +11 -11
  68. package/app/components/aside/minor/news/elements/P.vue +14 -14
  69. package/app/components/aside/minor/news/elements/Ref.vue +59 -58
  70. package/app/components/aside/minor/news/elements/Text.vue +18 -18
  71. package/app/components/indexPage/IndexPagePersons.vue +116 -117
  72. package/app/components/main/MainAction.vue +26 -26
  73. package/app/components/main/MainBreadcrumbs.vue +28 -28
  74. package/app/components/main/MainContentChild.vue +44 -47
  75. package/app/components/main/MainContentChildren.vue +13 -14
  76. package/app/components/main/MainDecoration.vue +15 -15
  77. package/app/components/main/MainDescription.vue +13 -13
  78. package/app/components/main/MainFlag.vue +129 -133
  79. package/app/components/main/MainFlags.vue +17 -17
  80. package/app/components/main/MainGlow.vue +12 -12
  81. package/app/components/main/MainQuickLink.vue +90 -91
  82. package/app/components/main/MainQuickLinks.vue +40 -40
  83. package/app/components/main/MainQuote.vue +149 -161
  84. package/app/components/main/MainQuoteLoader.vue +86 -86
  85. package/app/components/main/MainSection.vue +44 -44
  86. package/app/components/main/MainSectionPreamble.vue +5 -5
  87. package/app/components/main/MainSubTitle.vue +11 -12
  88. package/app/components/main/MainTitle.vue +32 -32
  89. package/app/components/main/MainTopicPartPage.vue +88 -88
  90. package/app/components/main/MainTopicPartSwitch.vue +67 -71
  91. package/app/components/main/connections/Deps.vue +30 -34
  92. package/app/components/main/connections/Externals.vue +80 -104
  93. package/app/components/main/connections/MainConnections.vue +90 -94
  94. package/app/components/main/connections/MainConnectionsButton.vue +81 -81
  95. package/app/components/main/connections/ScrollPane.vue +10 -10
  96. package/app/components/main/contentStats/Item.vue +28 -34
  97. package/app/components/main/contentStats/ItemElement.vue +19 -19
  98. package/app/components/main/contentStats/ItemMaterials.vue +11 -11
  99. package/app/components/main/contentStats/MainContentStats.vue +50 -53
  100. package/app/components/preview/Preview.vue +110 -118
  101. package/app/components/preview/PreviewError.vue +4 -4
  102. package/app/components/preview/PreviewLoading.vue +3 -3
  103. package/app/components/preview/PreviewScreen.vue +48 -48
  104. package/app/components/preview/PreviewScreenButton.vue +27 -27
  105. package/app/components/preview/screen/ContentPage.vue +27 -30
  106. package/app/components/preview/screen/DirectLink.vue +13 -13
  107. package/app/components/preview/screen/Unique.vue +31 -32
  108. package/app/components/site/SiteAside.vue +50 -51
  109. package/app/components/site/SiteAsideOverlay.vue +8 -8
  110. package/app/components/site/SiteMain.vue +11 -11
  111. package/app/components/transition/Fade.vue +16 -16
  112. package/app/components/transition/Slide.vue +27 -27
  113. package/app/components/tree/TreeContainer.vue +3 -3
  114. package/app/components/tree/TreeItem.vue +27 -31
  115. package/app/composables/ads.ts +11 -11
  116. package/app/composables/analytics.ts +102 -102
  117. package/app/composables/appElements.ts +21 -21
  118. package/app/composables/aside.ts +15 -15
  119. package/app/composables/asideMajorPane.ts +82 -82
  120. package/app/composables/asideMinor.ts +109 -109
  121. package/app/composables/contentNav.ts +7 -7
  122. package/app/composables/favicon.ts +103 -108
  123. package/app/composables/file.ts +4 -3
  124. package/app/composables/formatText.ts +100 -100
  125. package/app/composables/loading.ts +26 -26
  126. package/app/composables/mainContent.ts +22 -22
  127. package/app/composables/og.ts +184 -182
  128. package/app/composables/phrases.ts +98 -98
  129. package/app/composables/preview.ts +44 -44
  130. package/app/composables/route.ts +4 -2
  131. package/app/composables/theme.ts +47 -51
  132. package/app/composables/url.ts +19 -11
  133. package/app/formatters/ru.ts +14 -14
  134. package/app/pages/article/[...articleId].vue +12 -12
  135. package/app/pages/book/[...bookId].vue +56 -56
  136. package/app/pages/contributor/[contributorId].vue +144 -150
  137. package/app/pages/contributors.vue +95 -102
  138. package/app/pages/group/[...groupId].vue +58 -58
  139. package/app/pages/index.vue +113 -117
  140. package/app/pages/page/[...pageId].vue +60 -60
  141. package/app/pages/practice/[...practiceId].vue +12 -12
  142. package/app/pages/sponsors.vue +88 -92
  143. package/app/pages/summary/[...summaryId].vue +12 -12
  144. package/app/plugins/appSetup/client/htmlBranding.ts +6 -6
  145. package/app/plugins/appSetup/client/welcome.ts +37 -35
  146. package/app/plugins/appSetup/config.ts +6 -6
  147. package/app/plugins/appSetup/global.ts +3 -3
  148. package/app/plugins/appSetup/index.ts +27 -28
  149. package/app/plugins/prerender.server.ts +40 -40
  150. package/app/router.options.ts +5 -5
  151. package/app/scripts/theme.js +21 -24
  152. package/app/styles/main.css +128 -124
  153. package/bin/erudit.js +12 -0
  154. package/modules/erudit/env.ts +8 -0
  155. package/modules/erudit/globals/content.ts +4 -4
  156. package/modules/erudit/globals/contributor.ts +1 -1
  157. package/modules/erudit/globals/eruditConfig.ts +5 -10
  158. package/modules/erudit/globals/problem.ts +1 -1
  159. package/modules/erudit/globals/prose.ts +1 -1
  160. package/modules/erudit/globals/public.ts +18 -18
  161. package/modules/erudit/index.ts +50 -60
  162. package/modules/erudit/logger.ts +10 -10
  163. package/modules/erudit/setup/elements/appTemplate.ts +44 -45
  164. package/modules/erudit/setup/elements/globalTemplate.ts +82 -82
  165. package/modules/erudit/setup/elements/globalTypes.ts +259 -273
  166. package/modules/erudit/setup/elements/setup.ts +163 -167
  167. package/modules/erudit/setup/elements/shared.ts +10 -10
  168. package/modules/erudit/setup/elements/tagsTable.ts +28 -28
  169. package/modules/erudit/setup/fullRestart.ts +61 -71
  170. package/modules/erudit/setup/globals.ts +206 -196
  171. package/modules/erudit/setup/publicAssets.ts +43 -52
  172. package/modules/erudit/setup/runtimeConfig.ts +106 -58
  173. package/modules/erudit/watcher.ts +20 -27
  174. package/nuxt.config.ts +102 -84
  175. package/package.json +51 -55
  176. package/server/api/aside/major/frontNav/book/[...shortId].ts +10 -10
  177. package/server/api/aside/major/frontNav/global.ts +5 -5
  178. package/server/api/aside/major/pages.ts +6 -6
  179. package/server/api/contributor/list.ts +60 -61
  180. package/server/api/contributor/page/[contributorId].ts +68 -68
  181. package/server/api/indexPage.ts +81 -81
  182. package/server/api/language/functions.ts +11 -11
  183. package/server/api/language/phrase/[phraseKey].ts +35 -35
  184. package/server/api/main/content/[...contentTypePath].ts +149 -153
  185. package/server/api/news/batch/[batchIndex].ts +5 -5
  186. package/server/api/pageSponsors.ts +56 -58
  187. package/server/api/prerender/content.ts +79 -82
  188. package/server/api/prerender/default.ts +35 -35
  189. package/server/api/prerender/files.ts +10 -10
  190. package/server/api/prerender/frontNav.ts +13 -13
  191. package/server/api/prerender/language.ts +7 -7
  192. package/server/api/prerender/news.ts +8 -8
  193. package/server/api/prerender/quotes.ts +15 -15
  194. package/server/api/preview/contentPage/[...contentTypePath].ts +63 -63
  195. package/server/api/preview/contentUnique/[...contentTypePathUnique].ts +73 -81
  196. package/server/api/problemScript/[...problemScriptPath].ts +88 -92
  197. package/server/api/quote/data/[quoteId].ts +84 -87
  198. package/server/api/quote/ids.ts +3 -3
  199. package/server/erudit/build.ts +132 -137
  200. package/server/erudit/cameos/build.ts +161 -161
  201. package/server/erudit/config.ts +13 -13
  202. package/server/erudit/content/global/build.ts +300 -297
  203. package/server/erudit/content/global/singleton.ts +5 -5
  204. package/server/erudit/content/nav/build.ts +459 -463
  205. package/server/erudit/content/nav/front.ts +125 -127
  206. package/server/erudit/content/nav/repository/books.ts +37 -40
  207. package/server/erudit/content/nav/repository/get.ts +33 -33
  208. package/server/erudit/content/nav/repository/hasChildren.ts +5 -5
  209. package/server/erudit/content/nav/repository/hasNav.ts +3 -3
  210. package/server/erudit/content/nav/repository/hasParent.ts +5 -5
  211. package/server/erudit/content/nav/repository/id.ts +9 -9
  212. package/server/erudit/content/nav/repository/index.ts +9 -9
  213. package/server/erudit/content/nav/repository/order.ts +14 -14
  214. package/server/erudit/content/nav/repository/previousNext.ts +35 -35
  215. package/server/erudit/content/nav/repository/walk.ts +127 -127
  216. package/server/erudit/content/nav/setup.ts +13 -13
  217. package/server/erudit/content/nav/types.ts +24 -24
  218. package/server/erudit/content/repository/breadcrumbs.ts +24 -24
  219. package/server/erudit/content/repository/children.ts +47 -47
  220. package/server/erudit/content/repository/connections.ts +35 -35
  221. package/server/erudit/content/repository/contentLink.ts +16 -16
  222. package/server/erudit/content/repository/decoration.ts +23 -23
  223. package/server/erudit/content/repository/deps.ts +121 -84
  224. package/server/erudit/content/repository/description.ts +11 -11
  225. package/server/erudit/content/repository/elementSnippets.ts +105 -105
  226. package/server/erudit/content/repository/externals.ts +50 -50
  227. package/server/erudit/content/repository/flags.ts +33 -33
  228. package/server/erudit/content/repository/seo.ts +12 -12
  229. package/server/erudit/content/repository/stats.ts +97 -97
  230. package/server/erudit/content/repository/title.ts +27 -27
  231. package/server/erudit/content/repository/topicParts.ts +39 -39
  232. package/server/erudit/content/repository/unique.ts +76 -76
  233. package/server/erudit/content/resolve/book.ts +29 -32
  234. package/server/erudit/content/resolve/group.ts +34 -39
  235. package/server/erudit/content/resolve/index.ts +272 -290
  236. package/server/erudit/content/resolve/page.ts +80 -87
  237. package/server/erudit/content/resolve/topic.ts +220 -246
  238. package/server/erudit/content/resolve/utils/contentError.ts +10 -10
  239. package/server/erudit/content/resolve/utils/insertContentItem.ts +113 -122
  240. package/server/erudit/content/resolve/utils/insertContentResolved.ts +126 -132
  241. package/server/erudit/content/search.ts +146 -163
  242. package/server/erudit/contributors/build.ts +158 -166
  243. package/server/erudit/contributors/global.ts +3 -3
  244. package/server/erudit/contributors/repository/avatarUrl.ts +10 -10
  245. package/server/erudit/contributors/repository/contributions.ts +171 -178
  246. package/server/erudit/contributors/repository/count.ts +3 -3
  247. package/server/erudit/contributors/search.ts +34 -34
  248. package/server/erudit/db/repository/pushFile.ts +23 -26
  249. package/server/erudit/db/repository/pushProblemScript.ts +19 -19
  250. package/server/erudit/db/repository/pushProseLink.ts +40 -40
  251. package/server/erudit/db/schema/cameos.ts +7 -7
  252. package/server/erudit/db/schema/content.ts +18 -18
  253. package/server/erudit/db/schema/contentContributions.ts +15 -15
  254. package/server/erudit/db/schema/contentDeps.ts +21 -21
  255. package/server/erudit/db/schema/contentElementStats.ts +20 -20
  256. package/server/erudit/db/schema/contentProseLinks.ts +23 -23
  257. package/server/erudit/db/schema/contentSnippets.ts +15 -15
  258. package/server/erudit/db/schema/contentToc.ts +16 -16
  259. package/server/erudit/db/schema/contentUniques.ts +19 -25
  260. package/server/erudit/db/schema/contributors.ts +12 -12
  261. package/server/erudit/db/schema/files.ts +11 -11
  262. package/server/erudit/db/schema/groups.ts +6 -6
  263. package/server/erudit/db/schema/index.ts +17 -17
  264. package/server/erudit/db/schema/news.ts +7 -7
  265. package/server/erudit/db/schema/pages.ts +7 -7
  266. package/server/erudit/db/schema/problemScripts.ts +14 -14
  267. package/server/erudit/db/schema/sponsors.ts +9 -9
  268. package/server/erudit/db/schema/topics.ts +9 -9
  269. package/server/erudit/db/setup.ts +62 -62
  270. package/server/erudit/db/types.ts +10 -10
  271. package/server/erudit/global.ts +38 -33
  272. package/server/erudit/importer.ts +94 -97
  273. package/server/erudit/index.ts +96 -90
  274. package/server/erudit/language/list/en.ts +116 -116
  275. package/server/erudit/language/list/ru.ts +120 -120
  276. package/server/erudit/language/list.ts +6 -6
  277. package/server/erudit/language/setup.ts +36 -36
  278. package/server/erudit/language/types.ts +16 -16
  279. package/server/erudit/logger.ts +73 -77
  280. package/server/erudit/news/build.ts +112 -114
  281. package/server/erudit/news/repository/batch.ts +61 -61
  282. package/server/erudit/path.ts +19 -0
  283. package/server/erudit/prose/repository/finalize.ts +68 -68
  284. package/server/erudit/prose/repository/get.ts +54 -54
  285. package/server/erudit/prose/repository/resolve.ts +17 -17
  286. package/server/erudit/prose/storage/callout.ts +16 -14
  287. package/server/erudit/prose/storage/image.ts +22 -20
  288. package/server/erudit/prose/storage/link.ts +222 -226
  289. package/server/erudit/prose/storage/problemScript.ts +23 -21
  290. package/server/erudit/prose/storage/video.ts +16 -14
  291. package/server/erudit/prose/transform/bundleProblemScript.ts +6 -6
  292. package/server/erudit/prose/transform/extensions.ts +15 -15
  293. package/server/erudit/quote/repository/ids.ts +31 -31
  294. package/server/erudit/repository.ts +96 -96
  295. package/server/erudit/sponsors/build.ts +161 -165
  296. package/server/erudit/sponsors/repository/avatarUrl.ts +10 -10
  297. package/server/erudit/sponsors/repository/count.ts +4 -4
  298. package/server/erudit/staticFile.ts +28 -28
  299. package/server/plugins/augmentCss.ts +17 -17
  300. package/server/plugins/lang.ts +5 -7
  301. package/server/plugins/metaViewport.ts +15 -15
  302. package/server/plugins/theme.ts +13 -13
  303. package/server/routes/file/[...path].ts +18 -18
  304. package/server/routes/robots.txt.ts +9 -9
  305. package/server/routes/search.json.gz.ts +76 -75
  306. package/server/routes/sitemap.xml.ts +83 -81
  307. package/shared/search/encoders.ts +10 -10
  308. package/shared/types/asideMajorPages.ts +2 -2
  309. package/shared/types/breadcrumbs.ts +3 -3
  310. package/shared/types/contentChildren.ts +10 -10
  311. package/shared/types/contentConnections.ts +27 -27
  312. package/shared/types/contentStats.ts +6 -6
  313. package/shared/types/elementSnippet.ts +14 -14
  314. package/shared/types/frontContentNav.ts +17 -17
  315. package/shared/types/indexPage.ts +20 -20
  316. package/shared/types/language.ts +174 -174
  317. package/shared/types/mainContent.ts +40 -40
  318. package/shared/types/news.ts +13 -13
  319. package/shared/types/preview.ts +28 -28
  320. package/shared/types/runtimeConfig.ts +29 -48
  321. package/shared/types/search.ts +32 -32
  322. package/shared/utils/contentTypePath.ts +44 -44
  323. package/shared/utils/icons.ts +7 -7
  324. package/shared/utils/pages.ts +19 -20
  325. package/shared/utils/stringColor.ts +8 -8
  326. package/shared/utils/toStringEqual.ts +13 -13
  327. package/shared/utils/zip.ts +64 -64
  328. package/test/shared/utils/zip.test.ts +8 -8
  329. package/tsconfig.json +15 -15
  330. package/bin/erudit.mjs +0 -2
  331. package/modules/erudit/setup/aliases.ts +0 -17
  332. package/modules/erudit/setup/baseUrl.ts +0 -19
  333. package/modules/erudit/setup/nuxtConfig.ts +0 -62
  334. package/modules/erudit/setup/projectConfig.ts +0 -115
  335. package/shared/utils/slasher.ts +0 -64
  336. package/test/shared/utils/slasher.test.ts +0 -75
@@ -1,132 +1,132 @@
1
- <script lang="ts" setup>
2
- import NewsItem from './NewsItem.vue';
3
-
4
- interface NewsCache {
5
- total?: number;
6
- items: NewsItem[];
7
- newIndices: number[];
8
- nextIndex?: number;
9
- }
10
-
11
- const STORAGE_KEY = 'last-viewed-news-date';
12
- const newsTotal = ref(0);
13
- const newsItems = ref<NewsItem[]>([]);
14
- const newNewsItems = ref<Set<number>>(new Set());
15
- const nextBatchIndex = ref<number | undefined>();
16
- const newsLoading = ref(false);
17
-
18
- const nuxtApp = useNuxtApp();
19
-
20
- function getCache(): NewsCache | undefined {
21
- return nuxtApp.payload.data['news'] as NewsCache | undefined;
22
- }
23
-
24
- function updateCache() {
25
- nuxtApp.payload.data['news'] = {
26
- total: newsTotal.value || undefined,
27
- items: newsItems.value,
28
- newIndices: Array.from(newNewsItems.value),
29
- nextIndex: nextBatchIndex.value,
30
- } as NewsCache;
31
- }
32
-
33
- function getLastViewedDate(): string | null {
34
- return localStorage.getItem(STORAGE_KEY);
35
- }
36
-
37
- function updateLastViewedDate(date: string) {
38
- localStorage.setItem(STORAGE_KEY, date);
39
- }
40
-
41
- async function fetchNews(index: number) {
42
- newsLoading.value = true;
43
-
44
- try {
45
- const newsBatch = await $fetch<NewsBatch>(`/api/news/batch/${index}`, {
46
- responseType: 'json',
47
- });
48
-
49
- if (index === 0) {
50
- newsTotal.value = newsBatch.total!;
51
- handleNewNewsItems(newsBatch.items);
52
- }
53
-
54
- newsItems.value = newsItems.value.concat(newsBatch.items);
55
- nextBatchIndex.value = newsBatch.nextIndex;
56
-
57
- updateCache();
58
- } catch (error) {
59
- console.error('Error fetching news:', error);
60
- } finally {
61
- newsLoading.value = false;
62
- }
63
- }
64
-
65
- function handleNewNewsItems(items: NewsItem[]) {
66
- if (items.length === 0) return;
67
-
68
- const lastViewedDate = getLastViewedDate();
69
- const latestItemDate = items[0]!.date;
70
-
71
- if (lastViewedDate) {
72
- const newItems = items
73
- .map((item, idx) => (item.date > lastViewedDate ? idx : -1))
74
- .filter((idx) => idx !== -1);
75
-
76
- // Only mark items as new if some (but not all) are new
77
- if (newItems.length > 0 && newItems.length < items.length) {
78
- newNewsItems.value = new Set(newItems);
79
- }
80
- }
81
-
82
- updateLastViewedDate(latestItemDate);
83
- }
84
-
85
- const cache = getCache();
86
- if (cache) {
87
- newsTotal.value = cache.total || 0;
88
- newsItems.value = cache.items;
89
- newNewsItems.value = new Set(cache.newIndices);
90
- nextBatchIndex.value = cache.nextIndex;
91
- } else {
92
- await fetchNews(0);
93
- }
94
-
95
- const phrase = await usePhrases('news', 'no_news', 'show_more');
96
- </script>
97
-
98
- <template>
99
- <AsideMinorPane>
100
- <div class="flex h-full w-full flex-col">
101
- <AsideMinorPlainHeader
102
- icon="bell"
103
- :title="phrase!.news"
104
- :count="newsTotal === 0 ? undefined : newsTotal"
105
- />
106
- <section v-if="newsItems.length === 0">
107
- <AsidePlainMessage :text="phrase.no_news" />
108
- </section>
109
- <ScrollHolder class="flex-1">
110
- <NewsItem
111
- v-for="(item, index) in newsItems"
112
- :item
113
- :isNew="newNewsItems.has(index)"
114
- />
115
- <TransitionFade>
116
- <button
117
- v-if="nextBatchIndex !== undefined"
118
- @click="fetchNews(nextBatchIndex)"
119
- :disabled="newsLoading"
120
- class="my-big px-normal py-small bg-bg-accent
121
- hocus:border-text-disabled gap-normal m-auto flex
122
- w-auto cursor-pointer items-center rounded border-2
123
- border-transparent text-sm transition-[border]"
124
- >
125
- <Loading v-if="newsLoading" />
126
- <span>{{ phrase.show_more }}</span>
127
- </button>
128
- </TransitionFade>
129
- </ScrollHolder>
130
- </div>
131
- </AsideMinorPane>
132
- </template>
1
+ <script lang="ts" setup>
2
+ import NewsItem from './NewsItem.vue';
3
+
4
+ interface NewsCache {
5
+ total?: number;
6
+ items: NewsItem[];
7
+ newIndices: number[];
8
+ nextIndex?: number;
9
+ }
10
+
11
+ const STORAGE_KEY = 'last-viewed-news-date';
12
+ const newsTotal = ref(0);
13
+ const newsItems = ref<NewsItem[]>([]);
14
+ const newNewsItems = ref<Set<number>>(new Set());
15
+ const nextBatchIndex = ref<number | undefined>();
16
+ const newsLoading = ref(false);
17
+
18
+ const nuxtApp = useNuxtApp();
19
+
20
+ function getCache(): NewsCache | undefined {
21
+ return nuxtApp.payload.data['news'] as NewsCache | undefined;
22
+ }
23
+
24
+ function updateCache() {
25
+ nuxtApp.payload.data['news'] = {
26
+ total: newsTotal.value || undefined,
27
+ items: newsItems.value,
28
+ newIndices: Array.from(newNewsItems.value),
29
+ nextIndex: nextBatchIndex.value,
30
+ } as NewsCache;
31
+ }
32
+
33
+ function getLastViewedDate(): string | null {
34
+ return localStorage.getItem(STORAGE_KEY);
35
+ }
36
+
37
+ function updateLastViewedDate(date: string) {
38
+ localStorage.setItem(STORAGE_KEY, date);
39
+ }
40
+
41
+ async function fetchNews(index: number) {
42
+ newsLoading.value = true;
43
+
44
+ try {
45
+ const newsBatch = await $fetch<NewsBatch>(`/api/news/batch/${index}`, {
46
+ responseType: 'json',
47
+ });
48
+
49
+ if (index === 0) {
50
+ newsTotal.value = newsBatch.total!;
51
+ handleNewNewsItems(newsBatch.items);
52
+ }
53
+
54
+ newsItems.value = newsItems.value.concat(newsBatch.items);
55
+ nextBatchIndex.value = newsBatch.nextIndex;
56
+
57
+ updateCache();
58
+ } catch (error) {
59
+ console.error('Error fetching news:', error);
60
+ } finally {
61
+ newsLoading.value = false;
62
+ }
63
+ }
64
+
65
+ function handleNewNewsItems(items: NewsItem[]) {
66
+ if (items.length === 0) return;
67
+
68
+ const lastViewedDate = getLastViewedDate();
69
+ const latestItemDate = items[0]!.date;
70
+
71
+ if (lastViewedDate) {
72
+ const newItems = items
73
+ .map((item, idx) => (item.date > lastViewedDate ? idx : -1))
74
+ .filter((idx) => idx !== -1);
75
+
76
+ // Only mark items as new if some (but not all) are new
77
+ if (newItems.length > 0 && newItems.length < items.length) {
78
+ newNewsItems.value = new Set(newItems);
79
+ }
80
+ }
81
+
82
+ updateLastViewedDate(latestItemDate);
83
+ }
84
+
85
+ const cache = getCache();
86
+ if (cache) {
87
+ newsTotal.value = cache.total || 0;
88
+ newsItems.value = cache.items;
89
+ newNewsItems.value = new Set(cache.newIndices);
90
+ nextBatchIndex.value = cache.nextIndex;
91
+ } else {
92
+ await fetchNews(0);
93
+ }
94
+
95
+ const phrase = await usePhrases('news', 'no_news', 'show_more');
96
+ </script>
97
+
98
+ <template>
99
+ <AsideMinorPane>
100
+ <div class="flex h-full w-full flex-col">
101
+ <AsideMinorPlainHeader
102
+ icon="bell"
103
+ :title="phrase!.news"
104
+ :count="newsTotal === 0 ? undefined : newsTotal"
105
+ />
106
+ <section v-if="newsItems.length === 0">
107
+ <AsidePlainMessage :text="phrase.no_news" />
108
+ </section>
109
+ <ScrollHolder class="flex-1">
110
+ <NewsItem
111
+ v-for="(item, index) in newsItems"
112
+ :item
113
+ :isNew="newNewsItems.has(index)"
114
+ />
115
+ <TransitionFade>
116
+ <button
117
+ v-if="nextBatchIndex !== undefined"
118
+ @click="fetchNews(nextBatchIndex)"
119
+ :disabled="newsLoading"
120
+ class="my-big px-normal py-small bg-bg-accent
121
+ hocus:border-text-disabled gap-normal m-auto flex w-auto
122
+ cursor-pointer items-center rounded border-2 border-transparent
123
+ text-sm transition-[border]"
124
+ >
125
+ <Loading v-if="newsLoading" />
126
+ <span>{{ phrase.show_more }}</span>
127
+ </button>
128
+ </TransitionFade>
129
+ </ScrollHolder>
130
+ </div>
131
+ </AsideMinorPane>
132
+ </template>
@@ -1,69 +1,69 @@
1
- <script lang="ts" setup>
2
- import { walkElements } from '@jsprose/core';
3
-
4
- import RenderNewsElement from './RenderNewsElement.vue';
5
-
6
- const { item, isNew } = defineProps<{
7
- item: NewsItem;
8
- isNew?: boolean;
9
- }>();
10
-
11
- const itemDate = new Date(item.date);
12
- const now = new Date();
13
-
14
- const isWithinThreeMonths = (() => {
15
- const threeMonthsAgo = new Date(now);
16
- threeMonthsAgo.setMonth(now.getMonth() - 3);
17
- return itemDate >= threeMonthsAgo && itemDate <= now;
18
- })();
19
-
20
- const dateOptions: Intl.DateTimeFormatOptions = {
21
- year: 'numeric',
22
- month: 'long',
23
- day: 'numeric',
24
- };
25
-
26
- const formattedTitle = itemDate.toLocaleDateString(undefined, dateOptions);
27
-
28
- // Prepopulate storage values in order not to fuck with provide/inject shit
29
- await walkElements(item.content.proseElement, async (element) => {
30
- if (element.storageKey) {
31
- const storageKey = element.storageKey;
32
- if (item.content.storage[storageKey] !== undefined) {
33
- (element as any).storageValue = item.content.storage[storageKey];
34
- }
35
- }
36
- });
37
- </script>
38
-
39
- <template>
40
- <div class="p-normal border-border border-b text-sm">
41
- <div
42
- class="mb-small gap-small flex items-center"
43
- :class="
44
- isNew
45
- ? 'font-semibold text-orange-700 dark:text-orange-300'
46
- : 'text-text-muted'
47
- "
48
- >
49
- <MyIcon v-if="isNew" name="flame" class="text-[1.2em]" />
50
- <NuxtTime
51
- :datetime="itemDate"
52
- v-bind="dateOptions"
53
- :relative="isWithinThreeMonths"
54
- :title="formattedTitle"
55
- class="cursor-help"
56
- />
57
- </div>
58
- <div
59
- :style="{
60
- '--linkColor': isNew
61
- ? 'light-dark(var(--color-orange-700),var(--color-orange-300))'
62
- : 'var(--color-brand)',
63
- }"
64
- class="gap-small flex flex-col text-[0.95em]"
65
- >
66
- <RenderNewsElement :element="item.content.proseElement" />
67
- </div>
68
- </div>
69
- </template>
1
+ <script lang="ts" setup>
2
+ import { walkElements } from '@jsprose/core';
3
+
4
+ import RenderNewsElement from './RenderNewsElement.vue';
5
+
6
+ const { item, isNew } = defineProps<{
7
+ item: NewsItem;
8
+ isNew?: boolean;
9
+ }>();
10
+
11
+ const itemDate = new Date(item.date);
12
+ const now = new Date();
13
+
14
+ const isWithinThreeMonths = (() => {
15
+ const threeMonthsAgo = new Date(now);
16
+ threeMonthsAgo.setMonth(now.getMonth() - 3);
17
+ return itemDate >= threeMonthsAgo && itemDate <= now;
18
+ })();
19
+
20
+ const dateOptions: Intl.DateTimeFormatOptions = {
21
+ year: 'numeric',
22
+ month: 'long',
23
+ day: 'numeric',
24
+ };
25
+
26
+ const formattedTitle = itemDate.toLocaleDateString(undefined, dateOptions);
27
+
28
+ // Prepopulate storage values in order not to fuck with provide/inject shit
29
+ await walkElements(item.content.proseElement, async (element) => {
30
+ if (element.storageKey) {
31
+ const storageKey = element.storageKey;
32
+ if (item.content.storage[storageKey] !== undefined) {
33
+ (element as any).storageValue = item.content.storage[storageKey];
34
+ }
35
+ }
36
+ });
37
+ </script>
38
+
39
+ <template>
40
+ <div class="p-normal border-border border-b text-sm">
41
+ <div
42
+ class="mb-small gap-small flex items-center"
43
+ :class="
44
+ isNew
45
+ ? 'font-semibold text-orange-700 dark:text-orange-300'
46
+ : 'text-text-muted'
47
+ "
48
+ >
49
+ <MyIcon v-if="isNew" name="flame" class="text-[1.2em]" />
50
+ <NuxtTime
51
+ :datetime="itemDate"
52
+ v-bind="dateOptions"
53
+ :relative="isWithinThreeMonths"
54
+ :title="formattedTitle"
55
+ class="cursor-help"
56
+ />
57
+ </div>
58
+ <div
59
+ :style="{
60
+ '--linkColor': isNew
61
+ ? 'light-dark(var(--color-orange-700),var(--color-orange-300))'
62
+ : 'var(--color-brand)',
63
+ }"
64
+ class="gap-small flex flex-col text-[0.95em]"
65
+ >
66
+ <RenderNewsElement :element="item.content.proseElement" />
67
+ </div>
68
+ </div>
69
+ </template>
@@ -1,42 +1,42 @@
1
- <script lang="ts" setup>
2
- import {
3
- inlinersSchema,
4
- mixSchema,
5
- textSchema,
6
- type AnySchema,
7
- type ProseElement,
8
- } from '@jsprose/core';
9
- import { paragraphSchema } from '@erudit-js/prose/elements/paragraph/core';
10
-
11
- import Mix from './elements/Mix.vue';
12
- import P from './elements/P.vue';
13
- import Text from './elements/Text.vue';
14
- import { refSchema } from '@erudit-js/prose/elements/link/reference/core';
15
- import Ref from './elements/Ref.vue';
16
-
17
- const { element } = defineProps<{ element: ProseElement<AnySchema> }>();
18
-
19
- const ElementComponent = (() => {
20
- switch (element.schemaName) {
21
- case textSchema.name:
22
- return Text;
23
- case paragraphSchema.name:
24
- return P;
25
- case refSchema.name:
26
- return Ref;
27
- case mixSchema.name:
28
- case inlinersSchema.name:
29
- return Mix;
30
- default:
31
- return h(
32
- 'span',
33
- { class: 'text-red-500 font-semibold font-mono' },
34
- `<${element.schemaName} />`,
35
- );
36
- }
37
- })();
38
- </script>
39
-
40
- <template>
41
- <ElementComponent v-if="element" :element />
42
- </template>
1
+ <script lang="ts" setup>
2
+ import {
3
+ inlinersSchema,
4
+ mixSchema,
5
+ textSchema,
6
+ type AnySchema,
7
+ type ProseElement,
8
+ } from '@jsprose/core';
9
+ import { paragraphSchema } from '@erudit-js/prose/elements/paragraph/core';
10
+
11
+ import Mix from './elements/Mix.vue';
12
+ import P from './elements/P.vue';
13
+ import Text from './elements/Text.vue';
14
+ import { refSchema } from '@erudit-js/prose/elements/link/reference/core';
15
+ import Ref from './elements/Ref.vue';
16
+
17
+ const { element } = defineProps<{ element: ProseElement<AnySchema> }>();
18
+
19
+ const ElementComponent = (() => {
20
+ switch (element.schemaName) {
21
+ case textSchema.name:
22
+ return Text;
23
+ case paragraphSchema.name:
24
+ return P;
25
+ case refSchema.name:
26
+ return Ref;
27
+ case mixSchema.name:
28
+ case inlinersSchema.name:
29
+ return Mix;
30
+ default:
31
+ return h(
32
+ 'span',
33
+ { class: 'text-red-500 font-semibold font-mono' },
34
+ `<${element.schemaName} />`,
35
+ );
36
+ }
37
+ })();
38
+ </script>
39
+
40
+ <template>
41
+ <ElementComponent v-if="element" :element />
42
+ </template>
@@ -1,11 +1,11 @@
1
- <script lang="ts" setup>
2
- import type { mixSchema, ProseElement } from '@jsprose/core';
3
-
4
- import RenderNewsElement from '../RenderNewsElement.vue';
5
-
6
- defineProps<{ element: ProseElement<typeof mixSchema> }>();
7
- </script>
8
-
9
- <template>
10
- <RenderNewsElement v-for="child of element.children" :element="child" />
11
- </template>
1
+ <script lang="ts" setup>
2
+ import type { mixSchema, ProseElement } from '@jsprose/core';
3
+
4
+ import RenderNewsElement from '../RenderNewsElement.vue';
5
+
6
+ defineProps<{ element: ProseElement<typeof mixSchema> }>();
7
+ </script>
8
+
9
+ <template>
10
+ <RenderNewsElement v-for="child of element.children" :element="child" />
11
+ </template>
@@ -1,14 +1,14 @@
1
- <script lang="ts" setup>
2
- import type { ProseElement } from '@jsprose/core';
3
- import type { paragraphSchema } from '@erudit-js/prose/elements/paragraph/core';
4
-
5
- import RenderNewsElement from '../RenderNewsElement.vue';
6
-
7
- defineProps<{ element: ProseElement<typeof paragraphSchema> }>();
8
- </script>
9
-
10
- <template>
11
- <p>
12
- <RenderNewsElement v-for="child of element.children" :element="child" />
13
- </p>
14
- </template>
1
+ <script lang="ts" setup>
2
+ import type { ProseElement } from '@jsprose/core';
3
+ import type { paragraphSchema } from '@erudit-js/prose/elements/paragraph/core';
4
+
5
+ import RenderNewsElement from '../RenderNewsElement.vue';
6
+
7
+ defineProps<{ element: ProseElement<typeof paragraphSchema> }>();
8
+ </script>
9
+
10
+ <template>
11
+ <p>
12
+ <RenderNewsElement v-for="child of element.children" :element="child" />
13
+ </p>
14
+ </template>