erudit 2.0.0-dev.9 → 3.0.0-dev.1

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 (237) hide show
  1. package/app/app.vue +172 -172
  2. package/app/components/Loading.vue +23 -23
  3. package/app/components/SiteAside.vue +382 -382
  4. package/app/components/SiteMain.vue +35 -35
  5. package/app/components/ads/BannerTemplate.vue +51 -51
  6. package/app/components/ads/BottomBanner.vue +45 -45
  7. package/app/components/ads/LeftBanner.vue +50 -50
  8. package/app/components/aside/AsideListItem.vue +74 -74
  9. package/app/components/aside/AsideMajor.vue +56 -56
  10. package/app/components/aside/AsideMinor.vue +71 -71
  11. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  12. package/app/components/aside/major/PaneSwitch.vue +54 -54
  13. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  14. package/app/components/aside/major/SiteInfo.vue +85 -85
  15. package/app/components/aside/major/panes/Language.vue +79 -79
  16. package/app/components/aside/major/panes/Pages.vue +34 -34
  17. package/app/components/aside/major/panes/Search.vue +11 -3
  18. package/app/components/aside/major/panes/nav/Nav.vue +91 -91
  19. package/app/components/aside/major/panes/nav/NavBook.vue +86 -86
  20. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  21. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  22. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  23. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  24. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  25. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  26. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  27. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  28. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  29. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  30. package/app/components/aside/major/panes/other/ItemGenerator.vue +15 -15
  31. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  32. package/app/components/aside/major/panes/other/Other.vue +16 -16
  33. package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
  34. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  35. package/app/components/aside/minor/AsideMinorPane.vue +15 -16
  36. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  37. package/app/components/aside/minor/Contribute.vue +145 -145
  38. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
  39. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
  40. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  41. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  42. package/app/components/aside/minor/topic/TopicToc.vue +203 -203
  43. package/app/components/aside/minor/topic/TopicTocItem.vue +31 -31
  44. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  45. package/app/components/bitran/BitranContent.vue +63 -63
  46. package/app/components/bitran/RenderWrapper.vue +10 -10
  47. package/app/components/contributor/ContributorAvatar.vue +43 -43
  48. package/app/components/contributor/ContributorListItem.vue +35 -35
  49. package/app/components/main/topic/MainTopic.vue +79 -79
  50. package/app/components/main/topic/TopicPartSwitch.vue +118 -118
  51. package/app/components/main/utils/Breadcrumb.vue +75 -75
  52. package/app/components/main/utils/ContentDecoration.vue +29 -29
  53. package/app/components/main/utils/ContentDescription.vue +19 -20
  54. package/app/components/main/utils/ContentFlag.vue +15 -16
  55. package/app/components/main/utils/ContentPopover.vue +176 -176
  56. package/app/components/main/utils/ContentPopovers.vue +105 -105
  57. package/app/components/main/utils/ContentReferences.vue +70 -76
  58. package/app/components/main/utils/ContentSection.vue +45 -42
  59. package/app/components/main/utils/ContentTitle.vue +39 -37
  60. package/app/components/main/utils/reference/ReferenceGroup.vue +38 -41
  61. package/app/components/main/utils/reference/ReferenceItem.vue +68 -64
  62. package/app/components/main/utils/reference/ReferenceSource.vue +116 -110
  63. package/app/components/preview/Preview.vue +177 -177
  64. package/app/components/preview/PreviewDisplay.vue +139 -139
  65. package/app/components/preview/PreviewFooterAction.vue +73 -73
  66. package/app/components/preview/PreviewLoading.vue +14 -15
  67. package/app/components/preview/PreviewScreen.vue +99 -99
  68. package/app/components/preview/display/Alert.vue +50 -50
  69. package/app/components/preview/display/Custom.vue +18 -18
  70. package/app/components/preview/display/GenericLink.vue +48 -48
  71. package/app/components/preview/display/PageLink.vue +20 -20
  72. package/app/components/preview/display/Unique.vue +49 -49
  73. package/app/components/transition/Fade.vue +19 -22
  74. package/app/components/tree/TreeContainer.vue +11 -12
  75. package/app/components/tree/TreeItem.vue +89 -89
  76. package/app/composables/bitran.ts +127 -127
  77. package/app/composables/bitranContent.ts +37 -37
  78. package/app/composables/bitranLocation.ts +7 -7
  79. package/app/composables/contentData.ts +36 -36
  80. package/app/composables/contentPage.ts +156 -156
  81. package/app/composables/contentRoute.ts +45 -45
  82. package/app/composables/darkMagic.ts +24 -24
  83. package/app/composables/externalApi.ts +63 -63
  84. package/app/composables/favicon.ts +8 -8
  85. package/app/composables/formatText.ts +86 -86
  86. package/app/composables/majorPane.ts +60 -60
  87. package/app/composables/phrases.ts +80 -80
  88. package/app/composables/theme.ts +29 -29
  89. package/app/composables/url.ts +33 -33
  90. package/app/pages/_test/preview.vue +110 -110
  91. package/app/pages/article/[...articleId].vue +3 -3
  92. package/app/pages/book/[...bookId].vue +47 -47
  93. package/app/pages/group/[...groupId].vue +65 -65
  94. package/app/pages/index.vue +32 -32
  95. package/app/pages/members.vue +6 -7
  96. package/app/pages/practice/[...practice].vue +3 -3
  97. package/app/pages/summary/[...summaryId].vue +3 -3
  98. package/app/scripts/_immediate.js +9 -4
  99. package/app/scripts/aside/index.ts +59 -59
  100. package/app/scripts/aside/major/nav.ts +26 -26
  101. package/app/scripts/aside/minor/state.ts +37 -37
  102. package/app/scripts/aside/minor/topic.ts +3 -3
  103. package/app/scripts/flag.ts +28 -28
  104. package/app/scripts/og.ts +27 -27
  105. package/app/scripts/preview/build.ts +73 -84
  106. package/app/scripts/preview/data/alert.ts +19 -19
  107. package/app/scripts/preview/data/custom.ts +8 -8
  108. package/app/scripts/preview/data/genericLink.ts +24 -24
  109. package/app/scripts/preview/data/pageLink.ts +20 -20
  110. package/app/scripts/preview/data/unique.ts +70 -70
  111. package/app/scripts/preview/data.ts +24 -26
  112. package/app/scripts/preview/display.ts +37 -37
  113. package/app/scripts/preview/footer.ts +9 -9
  114. package/app/scripts/preview/request.ts +51 -51
  115. package/app/scripts/preview/state.ts +63 -63
  116. package/app/styles/_immediate.css +7 -3
  117. package/app/styles/_util.scss +43 -50
  118. package/app/styles/_utils.scss +44 -44
  119. package/app/styles/app.scss +91 -91
  120. package/app/styles/def/_bp.scss +27 -24
  121. package/app/styles/def/_size.scss +7 -7
  122. package/app/styles/def/_z.scss +5 -5
  123. package/app/styles/default.scss +83 -85
  124. package/app/styles/normalize.scss +63 -63
  125. package/app/styles/partials/_darkMagic.scss +5 -7
  126. package/app/styles/partials/_fnav.scss +15 -18
  127. package/app/styles/partials/_preview.scss +5 -7
  128. package/globalPath.ts +21 -21
  129. package/globals/bitran.ts +47 -47
  130. package/globals/content.ts +22 -22
  131. package/globals/contributor.ts +5 -5
  132. package/globals/erudit.ts +5 -5
  133. package/globals/register.ts +18 -18
  134. package/languages/en.ts +95 -95
  135. package/languages/ru.ts +99 -99
  136. package/module/bitran.ts +34 -34
  137. package/module/config.ts +34 -34
  138. package/module/imports.ts +46 -46
  139. package/module/index.ts +47 -47
  140. package/module/logger.ts +10 -10
  141. package/module/paths.ts +22 -22
  142. package/module/restart.ts +61 -61
  143. package/nuxt.config.ts +111 -107
  144. package/package.json +3 -3
  145. package/server/api/aside/major/nav/bookIds.ts +5 -5
  146. package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -20
  147. package/server/api/aside/major/nav/global.ts +7 -7
  148. package/server/api/aside/minor/news.ts +7 -7
  149. package/server/api/aside/minor/path.ts +78 -78
  150. package/server/api/bitran/content/[location].ts +7 -7
  151. package/server/api/bitran/toc/[location].ts +7 -7
  152. package/server/api/content/data.ts +72 -72
  153. package/server/api/contributor/count.ts +6 -6
  154. package/server/api/fake/content.ts +11 -11
  155. package/server/api/fake/shared/languages.ts +12 -12
  156. package/server/api/language/functions.ts +12 -12
  157. package/server/api/language/phrase/[phraseId].ts +19 -19
  158. package/server/api/language/phraseIds.ts +8 -8
  159. package/server/api/preview/page/[...parts].ts +51 -51
  160. package/server/api/preview/unique/[location].ts +55 -55
  161. package/server/plugin/bitran/content.ts +187 -187
  162. package/server/plugin/bitran/location.ts +25 -25
  163. package/server/plugin/bitran/products/include.ts +230 -230
  164. package/server/plugin/bitran/products/link.ts +116 -116
  165. package/server/plugin/bitran/setup.ts +9 -9
  166. package/server/plugin/bitran/toc.ts +83 -83
  167. package/server/plugin/bitran/transpiler.ts +46 -46
  168. package/server/plugin/build/close.ts +10 -10
  169. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  170. package/server/plugin/build/jobs/content/generic.ts +176 -176
  171. package/server/plugin/build/jobs/content/parse.ts +100 -100
  172. package/server/plugin/build/jobs/content/path.ts +6 -6
  173. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  174. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  175. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  176. package/server/plugin/build/jobs/contributors.ts +66 -66
  177. package/server/plugin/build/jobs/language.ts +36 -36
  178. package/server/plugin/build/jobs/nav.ts +209 -209
  179. package/server/plugin/build/process.ts +25 -25
  180. package/server/plugin/build/rebuild.ts +55 -55
  181. package/server/plugin/build/setup.ts +21 -21
  182. package/server/plugin/content/absoluteId.ts +94 -94
  183. package/server/plugin/content/context.ts +112 -112
  184. package/server/plugin/db/entities/Book.ts +7 -7
  185. package/server/plugin/db/entities/Content.ts +49 -49
  186. package/server/plugin/db/entities/Contribution.ts +10 -10
  187. package/server/plugin/db/entities/Contributor.ts +16 -16
  188. package/server/plugin/db/entities/Group.ts +14 -14
  189. package/server/plugin/db/entities/Hash.ts +15 -15
  190. package/server/plugin/db/entities/Topic.ts +20 -20
  191. package/server/plugin/db/entities/Unique.ts +21 -21
  192. package/server/plugin/db/setup.ts +34 -34
  193. package/server/plugin/global.ts +18 -18
  194. package/server/plugin/importer.ts +12 -12
  195. package/server/plugin/index.ts +9 -9
  196. package/server/plugin/logger.ts +23 -23
  197. package/server/plugin/nav/node.ts +26 -26
  198. package/server/plugin/nav/utils.ts +129 -129
  199. package/server/plugin/repository/book.ts +21 -21
  200. package/server/plugin/repository/content.ts +238 -238
  201. package/server/plugin/repository/contributor.ts +8 -8
  202. package/server/plugin/repository/frontNav.ts +148 -148
  203. package/server/plugin/repository/topic.ts +32 -32
  204. package/server/tsconfig.json +7 -7
  205. package/shared/aside/minor.ts +50 -50
  206. package/shared/asset.ts +15 -15
  207. package/shared/bitran/context.ts +8 -8
  208. package/shared/bitran/default.ts +46 -46
  209. package/shared/bitran/link/Link.vue +167 -167
  210. package/shared/bitran/link/factory.ts +24 -24
  211. package/shared/bitran/link/languages/en.ts +7 -7
  212. package/shared/bitran/link/languages/ru.ts +7 -7
  213. package/shared/bitran/link/renderer.ts +21 -21
  214. package/shared/bitran/link/shared.ts +17 -17
  215. package/shared/bitran/link/target.ts +134 -134
  216. package/shared/bitran/link/transpiler.ts +10 -10
  217. package/shared/bitran/location.ts +166 -166
  218. package/shared/bitran/toc.ts +8 -8
  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 +25 -25
  231. package/shared/types/language.ts +75 -75
  232. package/shared/utils/objectsEqual.ts +4 -4
  233. package/shared/utils/stringColor.ts +9 -9
  234. package/test/bitran/link/target.test.ts +141 -141
  235. package/test/bitran/location.test.ts +143 -143
  236. package/tsconfig.json +8 -8
  237. package/utils/stress.ts +9 -9
@@ -1,203 +1,203 @@
1
- <script lang="ts" setup>
2
- import { headingName } from '@erudit-js/bitran-elements/heading/shared';
3
-
4
- import { stringifyBitranLocation } from '@shared/bitran/location';
5
- import type { TocItem } from '@erudit/shared/bitran/toc';
6
- import { topicLocation } from '../../../../../app/scripts/aside/minor/topic';
7
- import { injectAsideData } from '../../../../../app/scripts/aside/minor/state';
8
- import type { AsideMinorTopic } from '@shared/aside/minor';
9
-
10
- import TopicTocItem from './TopicTocItem.vue';
11
-
12
- interface RuntimeTocItem extends TocItem {
13
- /**
14
- * * `0` — Not active
15
- * * `1` — Active for `window` events
16
- * * `2` — Active for Intersection Observer and currently in viewport
17
- */
18
- _active: 0 | 1 | 2;
19
- _position: number;
20
- }
21
-
22
- type RuntimeToc = RuntimeTocItem[];
23
-
24
- const topicData = injectAsideData<AsideMinorTopic>();
25
- const phrase = await usePhrases('empty_toc');
26
- const runtimeToc = ref<RuntimeToc>();
27
- const tocStateKey = ref(0);
28
-
29
- watch(topicData, setupRuntimeToc);
30
- setupRuntimeToc();
31
-
32
- function setupRuntimeToc() {
33
- const _newToc: RuntimeToc = [];
34
-
35
- for (let i = 0; i < topicData.value.toc.length; i++) {
36
- _newToc.push({
37
- ...topicData.value.toc[i]!,
38
- _active: 0,
39
- _position: i,
40
- });
41
- }
42
-
43
- tocStateKey.value++;
44
- runtimeToc.value = _newToc;
45
- }
46
-
47
- //
48
- // Live TOC
49
- //
50
-
51
- let observer: IntersectionObserver;
52
- let id2TocItemIndex: Record<string, number> = {};
53
-
54
- const windowEvents = ['DOMContentLoaded', 'load', 'resize', 'scroll'];
55
- let headings: RuntimeTocItem[];
56
- let closestAboveHeading: RuntimeTocItem;
57
-
58
- function disableLiveToc() {
59
- // Live TOC heading with `window` events
60
-
61
- for (const event of windowEvents)
62
- window.removeEventListener(event, updateActiveTopHeading);
63
-
64
- headings = closestAboveHeading = null;
65
-
66
- // Live TOC with Intersection Observer
67
-
68
- id2TocItemIndex = null;
69
-
70
- observer?.disconnect();
71
- observer = null;
72
-
73
- //
74
-
75
- if (runtimeToc.value?.length) {
76
- for (const tocItem of runtimeToc.value) tocItem._active = 0;
77
- }
78
- }
79
-
80
- function enableLiveToc() {
81
- if (!runtimeToc.value?.length) return;
82
-
83
- // Live TOC heading with `window` events
84
-
85
- headings = runtimeToc.value.filter(
86
- (item) => item.productName === headingName,
87
- );
88
-
89
- for (const event of windowEvents)
90
- window.addEventListener(event, updateActiveTopHeading);
91
-
92
- updateActiveTopHeading();
93
-
94
- // Live TOC with Intersection Observer
95
-
96
- observer = new IntersectionObserver(intersectionTrigger);
97
- id2TocItemIndex = {};
98
-
99
- for (const tocItem of runtimeToc.value) {
100
- const id = tocItem.id;
101
- id2TocItemIndex[id] = tocItem._position;
102
- observer.observe(document.getElementById(id));
103
- }
104
- }
105
-
106
- function updateActiveTopHeading() {
107
- function getBottom(id: string) {
108
- const defaultBottom = 1;
109
- const element = document.getElementById(id);
110
- return element ? element.getBoundingClientRect().bottom : defaultBottom;
111
- }
112
-
113
- if (closestAboveHeading) {
114
- closestAboveHeading._active = closestAboveHeading._active === 2 ? 2 : 0;
115
- closestAboveHeading = null;
116
- }
117
-
118
- if (runtimeToc.value?.length) {
119
- let topIndex = 0;
120
- let bottomIndex = headings.length;
121
- let targetIndex = 0;
122
-
123
- while (topIndex < bottomIndex) {
124
- const middleIndex = ((topIndex + bottomIndex) / 2) | 0;
125
- const middleHeading = headings[middleIndex];
126
- const middleHeadingTop = getBottom(middleHeading.id);
127
-
128
- if (middleHeadingTop <= 0) {
129
- targetIndex = middleIndex;
130
- topIndex = middleIndex + 1;
131
- } else {
132
- bottomIndex = middleIndex;
133
- }
134
- }
135
-
136
- closestAboveHeading = headings[targetIndex];
137
- if (closestAboveHeading && closestAboveHeading._active < 2)
138
- closestAboveHeading._active =
139
- getBottom(closestAboveHeading.id) <= 0 ? 1 : 0;
140
- }
141
- }
142
-
143
- function intersectionTrigger(entries: IntersectionObserverEntry[]) {
144
- for (const entry of entries) {
145
- const tocItem = runtimeToc.value[id2TocItemIndex[entry.target.id]];
146
- tocItem._active = entry.isIntersecting
147
- ? 2
148
- : tocItem._active === 1
149
- ? 1
150
- : 0;
151
- }
152
- }
153
-
154
- onMounted(() => {
155
- watch(
156
- [topicData, topicLocation],
157
- () => {
158
- disableLiveToc();
159
-
160
- if (!topicData.value.location || !topicLocation.value) return;
161
-
162
- if (
163
- stringifyBitranLocation(topicData.value.location) ===
164
- stringifyBitranLocation(topicLocation.value)
165
- )
166
- enableLiveToc();
167
- },
168
- { immediate: true },
169
- );
170
- });
171
-
172
- onUnmounted(() => {
173
- disableLiveToc();
174
- });
175
- </script>
176
-
177
- <template>
178
- <section :class="$style.topicToc">
179
- <TreeContainer v-if="runtimeToc.length > 0">
180
- <TopicTocItem
181
- v-for="tocItem of runtimeToc"
182
- v-memo="[tocStateKey, tocItem.id, tocItem._active]"
183
- :active="!!tocItem._active"
184
- :tocItem
185
- />
186
- </TreeContainer>
187
- <div v-else :class="$style.tocEmpty">{{ phrase.empty_toc }}</div>
188
- </section>
189
- </template>
190
-
191
- <style lang="scss" module>
192
- .topicToc {
193
- flex: 1;
194
- overflow: auto;
195
- @include scroll();
196
- }
197
-
198
- .tocEmpty {
199
- padding: var(--gap);
200
- text-align: center;
201
- color: var(--textMuted);
202
- }
203
- </style>
1
+ <script lang="ts" setup>
2
+ import { headingName } from '@erudit-js/bitran-elements/heading/shared';
3
+
4
+ import { stringifyBitranLocation } from '@shared/bitran/location';
5
+ import type { TocItem } from '@erudit/shared/bitran/toc';
6
+ import { topicLocation } from '@app/scripts/aside/minor/topic';
7
+ import { injectAsideData } from '@app/scripts/aside/minor/state';
8
+ import type { AsideMinorTopic } from '@shared/aside/minor';
9
+
10
+ import TopicTocItem from './TopicTocItem.vue';
11
+
12
+ interface RuntimeTocItem extends TocItem {
13
+ /**
14
+ * * `0` — Not active
15
+ * * `1` — Active for `window` events
16
+ * * `2` — Active for Intersection Observer and currently in viewport
17
+ */
18
+ _active: 0 | 1 | 2;
19
+ _position: number;
20
+ }
21
+
22
+ type RuntimeToc = RuntimeTocItem[];
23
+
24
+ const topicData = injectAsideData<AsideMinorTopic>();
25
+ const phrase = await usePhrases('empty_toc');
26
+ const runtimeToc = ref<RuntimeToc>();
27
+ const tocStateKey = ref(0);
28
+
29
+ watch(topicData, setupRuntimeToc);
30
+ setupRuntimeToc();
31
+
32
+ function setupRuntimeToc() {
33
+ const _newToc: RuntimeToc = [];
34
+
35
+ for (let i = 0; i < topicData.value.toc.length; i++) {
36
+ _newToc.push({
37
+ ...topicData.value.toc[i]!,
38
+ _active: 0,
39
+ _position: i,
40
+ });
41
+ }
42
+
43
+ tocStateKey.value++;
44
+ runtimeToc.value = _newToc;
45
+ }
46
+
47
+ //
48
+ // Live TOC
49
+ //
50
+
51
+ let observer: IntersectionObserver;
52
+ let id2TocItemIndex: Record<string, number> = {};
53
+
54
+ const windowEvents = ['DOMContentLoaded', 'load', 'resize', 'scroll'];
55
+ let headings: RuntimeTocItem[];
56
+ let closestAboveHeading: RuntimeTocItem;
57
+
58
+ function disableLiveToc() {
59
+ // Live TOC heading with `window` events
60
+
61
+ for (const event of windowEvents)
62
+ window.removeEventListener(event, updateActiveTopHeading);
63
+
64
+ headings = closestAboveHeading = null;
65
+
66
+ // Live TOC with Intersection Observer
67
+
68
+ id2TocItemIndex = null;
69
+
70
+ observer?.disconnect();
71
+ observer = null;
72
+
73
+ //
74
+
75
+ if (runtimeToc.value?.length) {
76
+ for (const tocItem of runtimeToc.value) tocItem._active = 0;
77
+ }
78
+ }
79
+
80
+ function enableLiveToc() {
81
+ if (!runtimeToc.value?.length) return;
82
+
83
+ // Live TOC heading with `window` events
84
+
85
+ headings = runtimeToc.value.filter(
86
+ (item) => item.productName === headingName,
87
+ );
88
+
89
+ for (const event of windowEvents)
90
+ window.addEventListener(event, updateActiveTopHeading);
91
+
92
+ updateActiveTopHeading();
93
+
94
+ // Live TOC with Intersection Observer
95
+
96
+ observer = new IntersectionObserver(intersectionTrigger);
97
+ id2TocItemIndex = {};
98
+
99
+ for (const tocItem of runtimeToc.value) {
100
+ const id = tocItem.id;
101
+ id2TocItemIndex[id] = tocItem._position;
102
+ observer.observe(document.getElementById(id));
103
+ }
104
+ }
105
+
106
+ function updateActiveTopHeading() {
107
+ function getBottom(id: string) {
108
+ const defaultBottom = 1;
109
+ const element = document.getElementById(id);
110
+ return element ? element.getBoundingClientRect().bottom : defaultBottom;
111
+ }
112
+
113
+ if (closestAboveHeading) {
114
+ closestAboveHeading._active = closestAboveHeading._active === 2 ? 2 : 0;
115
+ closestAboveHeading = null;
116
+ }
117
+
118
+ if (runtimeToc.value?.length) {
119
+ let topIndex = 0;
120
+ let bottomIndex = headings.length;
121
+ let targetIndex = 0;
122
+
123
+ while (topIndex < bottomIndex) {
124
+ const middleIndex = ((topIndex + bottomIndex) / 2) | 0;
125
+ const middleHeading = headings[middleIndex];
126
+ const middleHeadingTop = getBottom(middleHeading.id);
127
+
128
+ if (middleHeadingTop <= 0) {
129
+ targetIndex = middleIndex;
130
+ topIndex = middleIndex + 1;
131
+ } else {
132
+ bottomIndex = middleIndex;
133
+ }
134
+ }
135
+
136
+ closestAboveHeading = headings[targetIndex];
137
+ if (closestAboveHeading && closestAboveHeading._active < 2)
138
+ closestAboveHeading._active =
139
+ getBottom(closestAboveHeading.id) <= 0 ? 1 : 0;
140
+ }
141
+ }
142
+
143
+ function intersectionTrigger(entries: IntersectionObserverEntry[]) {
144
+ for (const entry of entries) {
145
+ const tocItem = runtimeToc.value[id2TocItemIndex[entry.target.id]];
146
+ tocItem._active = entry.isIntersecting
147
+ ? 2
148
+ : tocItem._active === 1
149
+ ? 1
150
+ : 0;
151
+ }
152
+ }
153
+
154
+ onMounted(() => {
155
+ watch(
156
+ [topicData, topicLocation],
157
+ () => {
158
+ disableLiveToc();
159
+
160
+ if (!topicData.value.location || !topicLocation.value) return;
161
+
162
+ if (
163
+ stringifyBitranLocation(topicData.value.location) ===
164
+ stringifyBitranLocation(topicLocation.value)
165
+ )
166
+ enableLiveToc();
167
+ },
168
+ { immediate: true },
169
+ );
170
+ });
171
+
172
+ onUnmounted(() => {
173
+ disableLiveToc();
174
+ });
175
+ </script>
176
+
177
+ <template>
178
+ <section :class="$style.topicToc">
179
+ <TreeContainer v-if="runtimeToc.length > 0">
180
+ <TopicTocItem
181
+ v-for="tocItem of runtimeToc"
182
+ v-memo="[tocStateKey, tocItem.id, tocItem._active]"
183
+ :active="!!tocItem._active"
184
+ :tocItem
185
+ />
186
+ </TreeContainer>
187
+ <div v-else :class="$style.tocEmpty">{{ phrase.empty_toc }}</div>
188
+ </section>
189
+ </template>
190
+
191
+ <style lang="scss" module>
192
+ .topicToc {
193
+ flex: 1;
194
+ overflow: auto;
195
+ @include scroll();
196
+ }
197
+
198
+ .tocEmpty {
199
+ padding: var(--gap);
200
+ text-align: center;
201
+ color: var(--textMuted);
202
+ }
203
+ </style>
@@ -1,31 +1,31 @@
1
- <script lang="ts" setup>
2
- import type { TocItem } from '@erudit/shared/bitran/toc';
3
-
4
- const { tocItem } = defineProps<{ tocItem: TocItem; active: boolean }>();
5
-
6
- const productName = tocItem.productName;
7
- const productIcon = await useBitranElementIcon(productName);
8
- const productPhrase = await useBitranElementLanguage(productName);
9
-
10
- function tocItemClick(event: Event) {
11
- navigateTo({
12
- query: {
13
- element: tocItem.id,
14
- },
15
- });
16
- event.preventDefault();
17
- event.stopPropagation();
18
- return false;
19
- }
20
- </script>
21
-
22
- <template>
23
- <TreeItem
24
- :label="tocItem.title || productPhrase('_element_title')"
25
- :level="tocItem.level"
26
- :link="`?element=${tocItem.id}` /* Apply page hash! */"
27
- :svg="productIcon"
28
- :active
29
- @click="tocItemClick"
30
- />
31
- </template>
1
+ <script lang="ts" setup>
2
+ import type { TocItem } from '@erudit/shared/bitran/toc';
3
+
4
+ const { tocItem } = defineProps<{ tocItem: TocItem; active: boolean }>();
5
+
6
+ const productName = tocItem.productName;
7
+ const productIcon = await useBitranElementIcon(productName);
8
+ const productPhrase = await useBitranElementLanguage(productName);
9
+
10
+ function tocItemClick(event: Event) {
11
+ navigateTo({
12
+ query: {
13
+ element: tocItem.id,
14
+ },
15
+ });
16
+ event.preventDefault();
17
+ event.stopPropagation();
18
+ return false;
19
+ }
20
+ </script>
21
+
22
+ <template>
23
+ <TreeItem
24
+ :label="tocItem.title || productPhrase('_element_title')"
25
+ :level="tocItem.level"
26
+ :link="`?element=${tocItem.id}` /* Apply page hash! */"
27
+ :svg="productIcon"
28
+ :active
29
+ @click="tocItemClick"
30
+ />
31
+ </template>
@@ -1,40 +1,40 @@
1
- <script lang="ts" setup>
2
- const props = defineProps<{ stick?: 'top' | 'bottom' }>();
3
- const style = useCssModule();
4
-
5
- const classes = computed(() => {
6
- const _classes: string[] = [style.asideOverlayPane];
7
-
8
- if (props.stick === 'bottom') _classes.push(style.stickBottom);
9
-
10
- return _classes;
11
- });
12
- </script>
13
-
14
- <template>
15
- <section :class="classes">
16
- <slot></slot>
17
- </section>
18
- </template>
19
-
20
- <style lang="scss" module>
21
- @use '$/def/bp';
22
-
23
- .asideOverlayPane {
24
- position: absolute;
25
- z-index: 10;
26
- top: 0;
27
- left: 0;
28
- width: 100%;
29
- height: 100%;
30
- background: var(--bgAside);
31
-
32
- display: flex;
33
- flex-direction: column;
34
- justify-content: start;
35
-
36
- &.stickBottom {
37
- justify-content: end;
38
- }
39
- }
40
- </style>
1
+ <script lang="ts" setup>
2
+ const props = defineProps<{ stick?: 'top' | 'bottom' }>();
3
+ const style = useCssModule();
4
+
5
+ const classes = computed(() => {
6
+ const _classes: string[] = [style.asideOverlayPane];
7
+
8
+ if (props.stick === 'bottom') _classes.push(style.stickBottom);
9
+
10
+ return _classes;
11
+ });
12
+ </script>
13
+
14
+ <template>
15
+ <section :class="classes">
16
+ <slot></slot>
17
+ </section>
18
+ </template>
19
+
20
+ <style lang="scss" module>
21
+ @use '$/def/bp';
22
+
23
+ .asideOverlayPane {
24
+ position: absolute;
25
+ z-index: 10;
26
+ top: 0;
27
+ left: 0;
28
+ width: 100%;
29
+ height: 100%;
30
+ background: var(--bgAside);
31
+
32
+ display: flex;
33
+ flex-direction: column;
34
+ justify-content: start;
35
+
36
+ &.stickBottom {
37
+ justify-content: end;
38
+ }
39
+ }
40
+ </style>
@@ -1,63 +1,63 @@
1
- <script lang="ts" setup>
2
- import { Bitran, type BitranContent } from '@bitran-js/renderer-vue';
3
-
4
- import type { BitranContext } from '@shared/bitran/context';
5
-
6
- import RenderWrapper from './RenderWrapper.vue';
7
-
8
- const props = defineProps<{
9
- content: BitranContent;
10
- context: BitranContext;
11
- }>();
12
-
13
- const bitranTranspiler = await useBitranTranspiler();
14
- const bitranRenderers = await useBitranRenderers();
15
-
16
- const formatText = useFormatText();
17
-
18
- // onMounted(() => {
19
- // watch(urlElement, () => {
20
- // //console.log('Highlighting product:', urlElement.value);
21
- // }, { immediate: true });
22
- // });
23
- </script>
24
-
25
- <template>
26
- <Bitran
27
- :class="$style.eruditBitranContainer"
28
- :transpiler="bitranTranspiler"
29
- :renderers="bitranRenderers"
30
- :content
31
- :editMode="false"
32
- :formatText
33
- :RenderWrapper
34
- />
35
- </template>
36
-
37
- <style lang="scss" module>
38
- @use '@bitran-js/renderer-vue/scss/def' as bitranDef;
39
-
40
- .eruditBitranContainer {
41
- padding: var(--_pMainY) var(--_pMainX);
42
- padding-left: calc(var(--_pMainX) - #{bitranDef.$asideWidth});
43
-
44
- // Setting up Bitran
45
-
46
- --bitran_gap: var(--gap);
47
- --bitran_gapSmall: var(--gapSmall);
48
- --bitran_gapBig: var(--gapBig);
49
- --bitran_gapBlocks: var(--gapBig);
50
-
51
- --bitran_xPadding: var(--_pMainX);
52
- --bitran_transitionSpeed: var(--transitionSpeed);
53
- --bitran_transitionFunction: var(--transitionFunction);
54
-
55
- --bitran_fontMain: 'Noto Sans', sans-serif;
56
- --bitran_fontAlt: 'Noto Serif', serif;
57
-
58
- --bitran_text: var(--text);
59
- --bitran_textMuted: var(--textMuted);
60
- --bitran_textDimmed: var(--textDimmed);
61
- --bitran_textDisabled: var(--textDisabled);
62
- }
63
- </style>
1
+ <script lang="ts" setup>
2
+ import { Bitran, type BitranContent } from '@bitran-js/renderer-vue';
3
+
4
+ import type { BitranContext } from '@shared/bitran/context';
5
+
6
+ import RenderWrapper from './RenderWrapper.vue';
7
+
8
+ const props = defineProps<{
9
+ content: BitranContent;
10
+ context: BitranContext;
11
+ }>();
12
+
13
+ const bitranTranspiler = await useBitranTranspiler();
14
+ const bitranRenderers = await useBitranRenderers();
15
+
16
+ const formatText = useFormatText();
17
+
18
+ // onMounted(() => {
19
+ // watch(urlElement, () => {
20
+ // //console.log('Highlighting product:', urlElement.value);
21
+ // }, { immediate: true });
22
+ // });
23
+ </script>
24
+
25
+ <template>
26
+ <Bitran
27
+ :class="$style.eruditBitranContainer"
28
+ :transpiler="bitranTranspiler"
29
+ :renderers="bitranRenderers"
30
+ :content
31
+ :editMode="false"
32
+ :formatText
33
+ :RenderWrapper
34
+ />
35
+ </template>
36
+
37
+ <style lang="scss" module>
38
+ @use '@bitran-js/renderer-vue/scss/def' as bitranDef;
39
+
40
+ .eruditBitranContainer {
41
+ padding: var(--_pMainY) var(--_pMainX);
42
+ padding-left: calc(var(--_pMainX) - #{bitranDef.$asideWidth});
43
+
44
+ // Setting up Bitran
45
+
46
+ --bitran_gap: var(--gap);
47
+ --bitran_gapSmall: var(--gapSmall);
48
+ --bitran_gapBig: var(--gapBig);
49
+ --bitran_gapBlocks: var(--gapBig);
50
+
51
+ --bitran_xPadding: var(--_pMainX);
52
+ --bitran_transitionSpeed: var(--transitionSpeed);
53
+ --bitran_transitionFunction: var(--transitionFunction);
54
+
55
+ --bitran_fontMain: 'Noto Sans', sans-serif;
56
+ --bitran_fontAlt: 'Noto Serif', serif;
57
+
58
+ --bitran_text: var(--text);
59
+ --bitran_textMuted: var(--textMuted);
60
+ --bitran_textDimmed: var(--textDimmed);
61
+ --bitran_textDisabled: var(--textDisabled);
62
+ }
63
+ </style>