erudit 3.0.0-dev.17 → 3.0.0-dev.18

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 (233) hide show
  1. package/app/app.vue +193 -191
  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/aside/AsideListItem.vue +74 -74
  6. package/app/components/aside/AsideMajor.vue +56 -56
  7. package/app/components/aside/AsideMinor.vue +73 -73
  8. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  9. package/app/components/aside/major/PaneSwitch.vue +54 -54
  10. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  11. package/app/components/aside/major/SiteInfo.vue +85 -85
  12. package/app/components/aside/major/panes/Language.vue +79 -79
  13. package/app/components/aside/major/panes/Pages.vue +34 -34
  14. package/app/components/aside/major/panes/Search.vue +11 -11
  15. package/app/components/aside/major/panes/nav/Nav.vue +92 -92
  16. package/app/components/aside/major/panes/nav/NavBook.vue +95 -95
  17. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  18. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  19. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  20. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  21. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  22. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  23. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  24. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  25. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  26. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  27. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -13
  28. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  29. package/app/components/aside/major/panes/other/Other.vue +16 -16
  30. package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
  31. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  32. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  33. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  34. package/app/components/aside/minor/Contribute.vue +145 -145
  35. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
  36. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
  37. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  38. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  39. package/app/components/aside/minor/topic/TopicToc.vue +214 -214
  40. package/app/components/aside/minor/topic/TopicTocItem.vue +32 -32
  41. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  42. package/app/components/bitran/BitranContent.vue +91 -91
  43. package/app/components/bitran/RenderWrapper.vue +10 -10
  44. package/app/components/contributor/ContributorAvatar.vue +45 -45
  45. package/app/components/contributor/ContributorListItem.vue +35 -35
  46. package/app/components/main/topic/MainTopic.vue +88 -88
  47. package/app/components/main/topic/TopicPartSwitch.vue +118 -118
  48. package/app/components/main/utils/Breadcrumb.vue +74 -74
  49. package/app/components/main/utils/ContentDecoration.vue +29 -29
  50. package/app/components/main/utils/ContentDescription.vue +19 -19
  51. package/app/components/main/utils/ContentPopover.vue +188 -188
  52. package/app/components/main/utils/ContentPopovers.vue +111 -111
  53. package/app/components/main/utils/ContentReferences.vue +70 -70
  54. package/app/components/main/utils/ContentSection.vue +45 -45
  55. package/app/components/main/utils/ContentTitle.vue +63 -63
  56. package/app/components/main/utils/reference/ReferenceGroup.vue +38 -38
  57. package/app/components/main/utils/reference/ReferenceItem.vue +70 -70
  58. package/app/components/main/utils/reference/ReferenceSource.vue +120 -120
  59. package/app/components/preview/Preview.vue +186 -186
  60. package/app/components/preview/PreviewDisplay.vue +139 -139
  61. package/app/components/preview/PreviewFooterAction.vue +73 -73
  62. package/app/components/preview/PreviewLoading.vue +14 -14
  63. package/app/components/preview/PreviewScreen.vue +141 -141
  64. package/app/components/preview/display/Alert.vue +50 -50
  65. package/app/components/preview/display/Custom.vue +18 -18
  66. package/app/components/preview/display/GenericLink.vue +48 -48
  67. package/app/components/preview/display/PageLink.vue +22 -22
  68. package/app/components/preview/display/Unique.vue +55 -55
  69. package/app/components/transition/Fade.vue +19 -19
  70. package/app/components/tree/TreeContainer.vue +11 -11
  71. package/app/components/tree/TreeItem.vue +89 -89
  72. package/app/composables/adsAllowed.ts +11 -0
  73. package/app/composables/bitran.ts +108 -108
  74. package/app/composables/bitranContent.ts +96 -92
  75. package/app/composables/bitranLocation.ts +7 -7
  76. package/app/composables/contentData.ts +38 -38
  77. package/app/composables/contentPage.ts +168 -158
  78. package/app/composables/contentRoute.ts +45 -45
  79. package/app/composables/darkMagic.ts +24 -24
  80. package/app/composables/externalApi.ts +69 -69
  81. package/app/composables/favicon.ts +8 -8
  82. package/app/composables/formatText.ts +99 -99
  83. package/app/composables/majorPane.ts +60 -60
  84. package/app/composables/phrases.ts +65 -65
  85. package/app/composables/theme.ts +29 -29
  86. package/app/composables/url.ts +33 -33
  87. package/app/pages/_test/preview.vue +110 -110
  88. package/app/pages/article/[...articleId].vue +3 -3
  89. package/app/pages/book/[...bookId].vue +47 -47
  90. package/app/pages/group/[...groupId].vue +66 -66
  91. package/app/pages/index.vue +32 -32
  92. package/app/pages/members.vue +5 -6
  93. package/app/pages/practice/[...practice].vue +3 -3
  94. package/app/pages/summary/[...summaryId].vue +3 -3
  95. package/app/plugins/analytics.ts +8 -0
  96. package/app/plugins/prerender.server.ts +22 -22
  97. package/app/scripts/_immediate.js +9 -9
  98. package/app/scripts/aside/index.ts +59 -59
  99. package/app/scripts/aside/major/nav.ts +26 -26
  100. package/app/scripts/aside/minor/state.ts +37 -37
  101. package/app/scripts/aside/minor/topic.ts +3 -3
  102. package/app/scripts/flag.ts +28 -28
  103. package/app/scripts/og.ts +27 -27
  104. package/app/scripts/preview/build.ts +76 -76
  105. package/app/scripts/preview/data/alert.ts +19 -19
  106. package/app/scripts/preview/data/custom.ts +8 -8
  107. package/app/scripts/preview/data/genericLink.ts +24 -24
  108. package/app/scripts/preview/data/pageLink.ts +23 -23
  109. package/app/scripts/preview/data/unique.ts +72 -72
  110. package/app/scripts/preview/data.ts +24 -24
  111. package/app/scripts/preview/display.ts +37 -37
  112. package/app/scripts/preview/footer.ts +9 -9
  113. package/app/scripts/preview/request.ts +51 -51
  114. package/app/scripts/preview/state.ts +63 -63
  115. package/app/styles/_immediate.css +7 -7
  116. package/app/styles/_util.scss +43 -43
  117. package/app/styles/_utils.scss +44 -44
  118. package/app/styles/app.scss +91 -91
  119. package/app/styles/def/_bp.scss +27 -27
  120. package/app/styles/def/_size.scss +7 -7
  121. package/app/styles/def/_z.scss +5 -5
  122. package/app/styles/normalize.scss +49 -49
  123. package/app/styles/partials/_darkMagic.scss +5 -5
  124. package/app/styles/partials/_fnav.scss +15 -15
  125. package/app/styles/partials/_preview.scss +5 -5
  126. package/bin/erudit.mjs +2 -2
  127. package/const.ts +4 -4
  128. package/globalPath.ts +21 -21
  129. package/globals/bitran.ts +1 -1
  130. package/globals/content.ts +27 -27
  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 +94 -94
  135. package/languages/ru.ts +98 -98
  136. package/module/bitran.ts +66 -66
  137. package/module/config.ts +35 -35
  138. package/module/imports.ts +67 -67
  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 +131 -131
  144. package/package.json +4 -4
  145. package/server/api/aside/major/nav/bookIds.ts +5 -5
  146. package/server/api/aside/major/nav/bookNav/[...bookId].ts +17 -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 +82 -82
  150. package/server/api/bitran/content/[...location].ts +10 -10
  151. package/server/api/bitran/toc/[...location].ts +9 -9
  152. package/server/api/content/data.ts +75 -75
  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/prerender.ts +19 -120
  160. package/server/api/preview/page/[...parts].ts +78 -78
  161. package/server/api/preview/unique/[...location].ts +61 -61
  162. package/server/plugin/bitran/content.ts +237 -190
  163. package/server/plugin/bitran/elements/include.ts +229 -229
  164. package/server/plugin/bitran/location.ts +39 -39
  165. package/server/plugin/bitran/toc.ts +94 -94
  166. package/server/plugin/bitran/transpiler.ts +18 -18
  167. package/server/plugin/build/close.ts +12 -12
  168. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  169. package/server/plugin/build/jobs/content/generic.ts +191 -191
  170. package/server/plugin/build/jobs/content/parse.ts +113 -113
  171. package/server/plugin/build/jobs/content/path.ts +6 -6
  172. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  173. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  174. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  175. package/server/plugin/build/jobs/contributors.ts +66 -66
  176. package/server/plugin/build/jobs/language.ts +36 -36
  177. package/server/plugin/build/jobs/nav.ts +345 -345
  178. package/server/plugin/build/process.ts +32 -32
  179. package/server/plugin/build/rebuild.ts +66 -66
  180. package/server/plugin/build/setup.ts +19 -19
  181. package/server/plugin/content/context.ts +119 -119
  182. package/server/plugin/db/entities/Book.ts +7 -7
  183. package/server/plugin/db/entities/Content.ts +45 -45
  184. package/server/plugin/db/entities/Contribution.ts +10 -10
  185. package/server/plugin/db/entities/Contributor.ts +16 -16
  186. package/server/plugin/db/entities/File.ts +10 -10
  187. package/server/plugin/db/entities/Group.ts +14 -14
  188. package/server/plugin/db/entities/Hash.ts +15 -15
  189. package/server/plugin/db/entities/Topic.ts +20 -20
  190. package/server/plugin/db/entities/Unique.ts +21 -21
  191. package/server/plugin/db/reset.ts +12 -12
  192. package/server/plugin/db/setup.ts +49 -49
  193. package/server/plugin/global.ts +16 -16
  194. package/server/plugin/importer.ts +16 -16
  195. package/server/plugin/index.ts +9 -9
  196. package/server/plugin/logger.ts +23 -23
  197. package/server/plugin/nav/node.ts +27 -27
  198. package/server/plugin/nav/utils.ts +179 -175
  199. package/server/plugin/repository/book.ts +23 -21
  200. package/server/plugin/repository/content.ts +240 -240
  201. package/server/plugin/repository/contentId.ts +40 -40
  202. package/server/plugin/repository/contributor.ts +8 -8
  203. package/server/plugin/repository/file.ts +10 -10
  204. package/server/plugin/repository/frontNav.ts +145 -145
  205. package/server/plugin/repository/topic.ts +35 -35
  206. package/server/tsconfig.json +9 -9
  207. package/shared/aside/minor.ts +51 -51
  208. package/shared/asset.ts +22 -22
  209. package/shared/bitran/contentId.ts +56 -56
  210. package/shared/bitran/stringContent.ts +6 -6
  211. package/shared/bitran/toc.ts +8 -8
  212. package/shared/content/bookId.ts +12 -12
  213. package/shared/content/context.ts +9 -9
  214. package/shared/content/data/base.ts +32 -32
  215. package/shared/content/data/index.ts +5 -5
  216. package/shared/content/data/type/book.ts +5 -5
  217. package/shared/content/data/type/group.ts +6 -6
  218. package/shared/content/data/type/topic.ts +11 -11
  219. package/shared/content/previousNext.ts +9 -9
  220. package/shared/contributor.ts +5 -5
  221. package/shared/frontNav.ts +41 -41
  222. package/shared/icons.ts +38 -38
  223. package/shared/image.ts +5 -5
  224. package/shared/link.ts +28 -28
  225. package/shared/popover.ts +8 -8
  226. package/shared/types/language.ts +74 -74
  227. package/shared/utils/objectsEqual.ts +4 -4
  228. package/shared/utils/stringColor.ts +9 -9
  229. package/test/contentId.test.ts +91 -91
  230. package/tsconfig.json +8 -8
  231. package/utils/contentPath.ts +67 -67
  232. package/utils/slash.ts +11 -11
  233. package/utils/stress.ts +9 -9
@@ -1,69 +1,69 @@
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
- }
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
+ }
@@ -1,8 +1,8 @@
1
- import eruditConfig from '#erudit/config';
2
-
3
- export const defaultFavicon =
4
- eruditConfig.site?.favicon?.default || eruditAsset('favicon/default.svg');
5
-
6
- export function useFavicon() {
7
- return useState('favicon', () => defaultFavicon);
8
- }
1
+ import eruditConfig from '#erudit/config';
2
+
3
+ export const defaultFavicon =
4
+ eruditConfig.site?.favicon?.default || eruditAsset('favicon/default.svg');
5
+
6
+ export function useFavicon() {
7
+ return useState('favicon', () => defaultFavicon);
8
+ }
@@ -1,99 +1,99 @@
1
- import eruditConfig from '#erudit/config';
2
-
3
- export interface FormatState {
4
- quoteOpen: boolean;
5
- }
6
-
7
- const defaultFormatState: FormatState = {
8
- quoteOpen: false,
9
- };
10
-
11
- export type FormatFunction = (text: string, state?: FormatState) => string;
12
- export type FormatterFunction = (text: string, state: FormatState) => string;
13
-
14
- let formatFunction: FormatFunction;
15
-
16
- export function useFormatText() {
17
- if (!formatFunction) {
18
- const language = eruditConfig?.language;
19
- formatFunction = createFormatFunction(language);
20
- }
21
-
22
- return formatFunction;
23
- }
24
-
25
- function createFormatFunction(language?: string): FormatFunction {
26
- const formatters: FormatterFunction[] = [];
27
-
28
- //
29
- // Em Dashes
30
- //
31
-
32
- formatters.push((text) => text.replace(/(^| )--($| )/gm, '$1—$2'));
33
-
34
- //
35
- // Quotes
36
- //
37
-
38
- {
39
- const quoteSymbols: [string, string] = (() => {
40
- switch (language) {
41
- case 'ru':
42
- return ['«', '»'];
43
- default:
44
- return ['“', '”'];
45
- }
46
- })();
47
-
48
- formatters.push((text, state) => {
49
- return text.replaceAll(/"/gm, () => {
50
- return (state.quoteOpen = !state.quoteOpen)
51
- ? quoteSymbols[0]
52
- : quoteSymbols[1];
53
- });
54
- });
55
- }
56
-
57
- //
58
- // Ellipsis
59
- //
60
-
61
- formatters.push((text) => text.replace(/\.\.\./gm, '…'));
62
-
63
- //
64
- // Language specific formatters
65
- //
66
-
67
- if (language === 'ru') formatters.push(ruStickyPrepositions);
68
-
69
- //
70
- //
71
- //
72
-
73
- function formatText(
74
- text: string,
75
- state: FormatState = defaultFormatState,
76
- ): string {
77
- if (!text) return text;
78
-
79
- for (const formatter of formatters) text = formatter(text, state);
80
-
81
- return text;
82
- }
83
-
84
- return formatText;
85
- }
86
-
87
- //
88
- //
89
- //
90
-
91
- /**
92
- * Formats prepositions in Russian text so that they are always adjacent to the next word and are not left hanging “in the air” when the line breaks.
93
- */
94
- function ruStickyPrepositions(text: string): string {
95
- return text.replace(
96
- / (в|не|без|для|до|за|из|к|на|над|о|об|от|по|под|при|про|с|у|через|вокруг|около|после|перед|между|внутри|вне|из-за|из-под|ради|сквозь|среди|насчёт|вследствие|благодаря|несмотря|наперекор|вопреки|подле|возле|рядом|навстречу) /gimu,
97
- ' $1\xa0',
98
- );
99
- }
1
+ import eruditConfig from '#erudit/config';
2
+
3
+ export interface FormatState {
4
+ quoteOpen: boolean;
5
+ }
6
+
7
+ const defaultFormatState: FormatState = {
8
+ quoteOpen: false,
9
+ };
10
+
11
+ export type FormatFunction = (text: string, state?: FormatState) => string;
12
+ export type FormatterFunction = (text: string, state: FormatState) => string;
13
+
14
+ let formatFunction: FormatFunction;
15
+
16
+ export function useFormatText() {
17
+ if (!formatFunction) {
18
+ const language = eruditConfig?.language;
19
+ formatFunction = createFormatFunction(language);
20
+ }
21
+
22
+ return formatFunction;
23
+ }
24
+
25
+ function createFormatFunction(language?: string): FormatFunction {
26
+ const formatters: FormatterFunction[] = [];
27
+
28
+ //
29
+ // Em Dashes
30
+ //
31
+
32
+ formatters.push((text) => text.replace(/(^| )--($| )/gm, '$1—$2'));
33
+
34
+ //
35
+ // Quotes
36
+ //
37
+
38
+ {
39
+ const quoteSymbols: [string, string] = (() => {
40
+ switch (language) {
41
+ case 'ru':
42
+ return ['«', '»'];
43
+ default:
44
+ return ['“', '”'];
45
+ }
46
+ })();
47
+
48
+ formatters.push((text, state) => {
49
+ return text.replaceAll(/"/gm, () => {
50
+ return (state.quoteOpen = !state.quoteOpen)
51
+ ? quoteSymbols[0]
52
+ : quoteSymbols[1];
53
+ });
54
+ });
55
+ }
56
+
57
+ //
58
+ // Ellipsis
59
+ //
60
+
61
+ formatters.push((text) => text.replace(/\.\.\./gm, '…'));
62
+
63
+ //
64
+ // Language specific formatters
65
+ //
66
+
67
+ if (language === 'ru') formatters.push(ruStickyPrepositions);
68
+
69
+ //
70
+ //
71
+ //
72
+
73
+ function formatText(
74
+ text: string,
75
+ state: FormatState = defaultFormatState,
76
+ ): string {
77
+ if (!text) return text;
78
+
79
+ for (const formatter of formatters) text = formatter(text, state);
80
+
81
+ return text;
82
+ }
83
+
84
+ return formatText;
85
+ }
86
+
87
+ //
88
+ //
89
+ //
90
+
91
+ /**
92
+ * Formats prepositions in Russian text so that they are always adjacent to the next word and are not left hanging “in the air” when the line breaks.
93
+ */
94
+ function ruStickyPrepositions(text: string): string {
95
+ return text.replace(
96
+ / (в|не|без|для|до|за|из|к|на|над|о|об|от|по|под|при|про|с|у|через|вокруг|около|после|перед|между|внутри|вне|из-за|из-под|ради|сквозь|среди|насчёт|вследствие|благодаря|несмотря|наперекор|вопреки|подле|возле|рядом|навстречу) /gimu,
97
+ ' $1\xa0',
98
+ );
99
+ }
@@ -1,60 +1,60 @@
1
- import type { Component } from 'vue';
2
-
3
- import type { MyIconName } from '#my-icons';
4
-
5
- import Nav from '@app/components/aside/major/panes/nav/Nav.vue';
6
- import Pages from '@app/components/aside/major/panes/Pages.vue';
7
- import Search from '@app/components/aside/major/panes/Search.vue';
8
- import Language from '@app/components/aside/major/panes/Language.vue';
9
- import Other from '@app/components/aside/major/panes/other/Other.vue';
10
-
11
- interface MajorPane {
12
- icon: MyIconName;
13
- phrase: EruditPhraseId;
14
- content: Component;
15
- }
16
-
17
- function definePane<TPane extends MajorPane>(pane: TPane) {
18
- return pane;
19
- }
20
-
21
- export const majorPanes = {
22
- index: definePane({ icon: 'book', phrase: 'index', content: Nav }),
23
- pages: definePane({ icon: 'file-lines', phrase: 'pages', content: Pages }),
24
- search: definePane({ icon: 'search', phrase: 'search', content: Search }),
25
- language: definePane({
26
- icon: 'globe',
27
- phrase: 'language',
28
- content: Language,
29
- }),
30
- other: definePane({
31
- icon: 'ellipsis-vertical',
32
- phrase: 'other',
33
- content: Other,
34
- }),
35
- };
36
-
37
- function getPaneOrder(paneKey: MajorPaneKey) {
38
- return Object.keys(majorPanes).indexOf(paneKey);
39
- }
40
-
41
- export type MajorPaneKey = keyof typeof majorPanes;
42
-
43
- export function useMajorPane() {
44
- const route = useRoute();
45
-
46
- const activePane = useState<MajorPaneKey>('major-pane', () => {
47
- switch (route.path) {
48
- case '/members':
49
- return 'pages';
50
- default:
51
- return 'index';
52
- }
53
- });
54
-
55
- return {
56
- panes: majorPanes,
57
- activePane,
58
- getPaneOrder,
59
- };
60
- }
1
+ import type { Component } from 'vue';
2
+
3
+ import type { MyIconName } from '#my-icons';
4
+
5
+ import Nav from '@app/components/aside/major/panes/nav/Nav.vue';
6
+ import Pages from '@app/components/aside/major/panes/Pages.vue';
7
+ import Search from '@app/components/aside/major/panes/Search.vue';
8
+ import Language from '@app/components/aside/major/panes/Language.vue';
9
+ import Other from '@app/components/aside/major/panes/other/Other.vue';
10
+
11
+ interface MajorPane {
12
+ icon: MyIconName;
13
+ phrase: EruditPhraseId;
14
+ content: Component;
15
+ }
16
+
17
+ function definePane<TPane extends MajorPane>(pane: TPane) {
18
+ return pane;
19
+ }
20
+
21
+ export const majorPanes = {
22
+ index: definePane({ icon: 'book', phrase: 'index', content: Nav }),
23
+ pages: definePane({ icon: 'file-lines', phrase: 'pages', content: Pages }),
24
+ search: definePane({ icon: 'search', phrase: 'search', content: Search }),
25
+ language: definePane({
26
+ icon: 'globe',
27
+ phrase: 'language',
28
+ content: Language,
29
+ }),
30
+ other: definePane({
31
+ icon: 'ellipsis-vertical',
32
+ phrase: 'other',
33
+ content: Other,
34
+ }),
35
+ };
36
+
37
+ function getPaneOrder(paneKey: MajorPaneKey) {
38
+ return Object.keys(majorPanes).indexOf(paneKey);
39
+ }
40
+
41
+ export type MajorPaneKey = keyof typeof majorPanes;
42
+
43
+ export function useMajorPane() {
44
+ const route = useRoute();
45
+
46
+ const activePane = useState<MajorPaneKey>('major-pane', () => {
47
+ switch (route.path) {
48
+ case '/members':
49
+ return 'pages';
50
+ default:
51
+ return 'index';
52
+ }
53
+ });
54
+
55
+ return {
56
+ panes: majorPanes,
57
+ activePane,
58
+ getPaneOrder,
59
+ };
60
+ }
@@ -1,65 +1,65 @@
1
- type PhraseCaller<T extends EruditPhraseId[]> = {
2
- [K in T[number]]: EruditPhrases[K];
3
- };
4
-
5
- const payloadKey = 'language';
6
-
7
- interface LanguagePayload {
8
- strPhrases: Partial<Record<EruditPhraseId, string>>;
9
- strFunctions: Record<string, string>;
10
- }
11
-
12
- const functions: Record<string, Function> = {};
13
- const functionPhrases: Record<string, Function> = {};
14
-
15
- const phraseApiRoute = (phraseId: EruditPhraseId) =>
16
- `/api/language/phrase/${phraseId}`;
17
- const functionsApiRoute = '/api/language/functions';
18
-
19
- export function usePhrases<T extends EruditPhraseId[]>(
20
- ...phraseIds: T
21
- ): Promise<PhraseCaller<T>> {
22
- const nuxt = useNuxtApp();
23
- const payload: LanguagePayload =
24
- (nuxt.static.data[payloadKey] ||=
25
- nuxt.payload.data[payloadKey] ||=
26
- {});
27
-
28
- const prepareFunctionsPromise = prepareFunctions(payload);
29
-
30
- return (async () => {
31
- await prepareFunctionsPromise;
32
-
33
- payload.strPhrases ||= {};
34
- const phraseCaller: any = {};
35
-
36
- for (const phraseId of phraseIds) {
37
- const apiRoute = phraseApiRoute(phraseId);
38
- const strPhrase = (payload.strPhrases[phraseId] ||= (await $fetch(
39
- apiRoute,
40
- { responseType: 'text' },
41
- )) as string);
42
-
43
- if (strPhrase.startsWith('~!~FUNC~!~')) {
44
- const strFunction = strPhrase.replace('~!~FUNC~!~', '');
45
- functionPhrases[phraseId] ||= new Function(strFunction).bind(
46
- functions,
47
- )();
48
- phraseCaller[phraseId] = functionPhrases[phraseId];
49
- } else {
50
- phraseCaller[phraseId] = strPhrase;
51
- }
52
- }
53
-
54
- return phraseCaller as PhraseCaller<T>;
55
- })();
56
- }
57
-
58
- async function prepareFunctions(payload: LanguagePayload) {
59
- if (payload?.strFunctions) return;
60
-
61
- payload.strFunctions = await $fetch(functionsApiRoute);
62
-
63
- for (const [funcName, strFunc] of Object.entries(payload.strFunctions))
64
- functions[funcName] = new Function(strFunc)();
65
- }
1
+ type PhraseCaller<T extends EruditPhraseId[]> = {
2
+ [K in T[number]]: EruditPhrases[K];
3
+ };
4
+
5
+ const payloadKey = 'language';
6
+
7
+ interface LanguagePayload {
8
+ strPhrases: Partial<Record<EruditPhraseId, string>>;
9
+ strFunctions: Record<string, string>;
10
+ }
11
+
12
+ const functions: Record<string, Function> = {};
13
+ const functionPhrases: Record<string, Function> = {};
14
+
15
+ const phraseApiRoute = (phraseId: EruditPhraseId) =>
16
+ `/api/language/phrase/${phraseId}`;
17
+ const functionsApiRoute = '/api/language/functions';
18
+
19
+ export function usePhrases<T extends EruditPhraseId[]>(
20
+ ...phraseIds: T
21
+ ): Promise<PhraseCaller<T>> {
22
+ const nuxt = useNuxtApp();
23
+ const payload: LanguagePayload =
24
+ (nuxt.static.data[payloadKey] ||=
25
+ nuxt.payload.data[payloadKey] ||=
26
+ {});
27
+
28
+ const prepareFunctionsPromise = prepareFunctions(payload);
29
+
30
+ return (async () => {
31
+ await prepareFunctionsPromise;
32
+
33
+ payload.strPhrases ||= {};
34
+ const phraseCaller: any = {};
35
+
36
+ for (const phraseId of phraseIds) {
37
+ const apiRoute = phraseApiRoute(phraseId);
38
+ const strPhrase = (payload.strPhrases[phraseId] ||= (await $fetch(
39
+ apiRoute,
40
+ { responseType: 'text' },
41
+ )) as string);
42
+
43
+ if (strPhrase.startsWith('~!~FUNC~!~')) {
44
+ const strFunction = strPhrase.replace('~!~FUNC~!~', '');
45
+ functionPhrases[phraseId] ||= new Function(strFunction).bind(
46
+ functions,
47
+ )();
48
+ phraseCaller[phraseId] = functionPhrases[phraseId];
49
+ } else {
50
+ phraseCaller[phraseId] = strPhrase;
51
+ }
52
+ }
53
+
54
+ return phraseCaller as PhraseCaller<T>;
55
+ })();
56
+ }
57
+
58
+ async function prepareFunctions(payload: LanguagePayload) {
59
+ if (payload?.strFunctions) return;
60
+
61
+ payload.strFunctions = await $fetch(functionsApiRoute);
62
+
63
+ for (const [funcName, strFunc] of Object.entries(payload.strFunctions))
64
+ functions[funcName] = new Function(strFunc)();
65
+ }
@@ -1,29 +1,29 @@
1
- const themes = ['auto', 'light', 'dark'] as const;
2
-
3
- export type Theme = (typeof themes)[number];
4
- export type BinaryTheme = 'light' | 'dark';
5
-
6
- export function useTheme() {
7
- const theme = useState<Theme>('theme', () => {
8
- return localStorage.getItem('theme') ?? ('auto' as any);
9
- });
10
-
11
- const binaryTheme = computed(() => {
12
- return theme.value === 'auto'
13
- ? window.matchMedia('(prefers-color-scheme: dark)').matches
14
- ? 'dark'
15
- : 'light'
16
- : theme.value;
17
- });
18
-
19
- const cycle = () => {
20
- theme.value =
21
- themes[(themes.indexOf(theme.value) + 1) % themes.length]!;
22
- };
23
-
24
- return {
25
- theme,
26
- binaryTheme,
27
- cycle,
28
- };
29
- }
1
+ const themes = ['auto', 'light', 'dark'] as const;
2
+
3
+ export type Theme = (typeof themes)[number];
4
+ export type BinaryTheme = 'light' | 'dark';
5
+
6
+ export function useTheme() {
7
+ const theme = useState<Theme>('theme', () => {
8
+ return localStorage.getItem('theme') ?? ('auto' as any);
9
+ });
10
+
11
+ const binaryTheme = computed(() => {
12
+ return theme.value === 'auto'
13
+ ? window.matchMedia('(prefers-color-scheme: dark)').matches
14
+ ? 'dark'
15
+ : 'light'
16
+ : theme.value;
17
+ });
18
+
19
+ const cycle = () => {
20
+ theme.value =
21
+ themes[(themes.indexOf(theme.value) + 1) % themes.length]!;
22
+ };
23
+
24
+ return {
25
+ theme,
26
+ binaryTheme,
27
+ cycle,
28
+ };
29
+ }