erudit 3.0.0-dev.10 → 3.0.0-dev.12
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.
- package/app/components/SiteMain.vue +2 -4
- package/app/components/aside/major/panes/Pages.vue +1 -1
- package/app/components/aside/major/panes/nav/Nav.vue +11 -6
- package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +1 -1
- package/app/components/aside/major/panes/other/ItemContent.vue +1 -1
- package/app/components/aside/major/panes/other/ItemGenerator.vue +1 -1
- package/app/components/aside/major/panes/other/ItemTheme.vue +1 -1
- package/app/components/aside/minor/Contribute.vue +2 -2
- package/app/components/aside/minor/content/AsideMinorContent.vue +1 -1
- package/app/components/aside/minor/topic/AsideMinorTopic.vue +1 -1
- package/app/components/aside/minor/topic/TopicContributors.vue +2 -2
- package/app/components/aside/minor/topic/TopicToc.vue +1 -6
- package/app/components/aside/minor/topic/TopicTocItem.vue +3 -1
- package/app/components/bitran/BitranContent.vue +1 -1
- package/app/components/main/utils/Breadcrumb.vue +1 -1
- package/app/components/preview/PreviewScreen.vue +2 -2
- package/app/components/preview/display/PageLink.vue +1 -1
- package/app/components/preview/display/Unique.vue +1 -1
- package/app/composables/bitran.ts +1 -1
- package/app/composables/bitranContent.ts +30 -6
- package/app/composables/contentPage.ts +8 -7
- package/app/composables/formatText.ts +21 -8
- package/app/composables/phrases.ts +0 -16
- package/app/plugins/prerender.server.ts +22 -0
- package/app/scripts/preview/build.ts +9 -6
- package/app/scripts/preview/data/pageLink.ts +1 -0
- package/app/styles/normalize.scss +0 -14
- package/globals/content.ts +5 -0
- package/module/imports.ts +6 -0
- package/module/index.ts +2 -0
- package/module/problemGenerators.ts +46 -0
- package/nuxt.config.ts +7 -5
- package/package.json +8 -8
- package/server/api/aside/minor/path.ts +19 -11
- package/server/api/bitran/content/[...location].ts +4 -2
- package/server/api/bitran/toc/[...location].ts +4 -2
- package/server/api/content/data.ts +5 -2
- package/server/api/prerender.ts +120 -0
- package/server/api/preview/page/[...parts].ts +30 -4
- package/server/api/preview/unique/{[location].ts → [...location].ts} +4 -3
- package/server/plugin/bitran/content.ts +45 -64
- package/server/plugin/bitran/elements/include.ts +52 -46
- package/server/plugin/bitran/location.ts +24 -10
- package/server/plugin/bitran/toc.ts +21 -2
- package/server/plugin/bitran/transpiler.ts +10 -1
- package/server/plugin/build/close.ts +3 -1
- package/server/plugin/build/jobs/content/generic.ts +12 -7
- package/server/plugin/build/jobs/content/type/group.ts +2 -2
- package/server/plugin/build/jobs/content/type/topic.ts +2 -2
- package/server/plugin/build/jobs/nav.ts +8 -11
- package/server/plugin/build/process.ts +2 -0
- package/server/plugin/build/rebuild.ts +12 -1
- package/server/plugin/content/context.ts +4 -1
- package/server/plugin/db/entities/Content.ts +0 -4
- package/server/plugin/db/entities/ContentId.ts +11 -0
- package/server/plugin/db/reset.ts +12 -0
- package/server/plugin/db/setup.ts +16 -1
- package/server/plugin/importer.ts +5 -1
- package/server/plugin/nav/utils.ts +4 -4
- package/server/plugin/repository/content.ts +4 -12
- package/server/plugin/repository/contentId.ts +26 -0
- package/server/plugin/repository/frontNav.ts +4 -4
- package/server/plugin/repository/topic.ts +4 -1
- package/shared/aside/minor.ts +2 -2
- package/shared/bitran/contentId.ts +4 -4
- package/shared/bitran/stringContent.ts +2 -2
- package/shared/content/bookId.ts +11 -0
- package/shared/frontNav.ts +1 -1
- package/utils/contentPath.ts +67 -0
- package/server/plugin/build/jobs/content/files.ts +0 -79
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<main :class="$style.main" erudit-main>
|
|
3
|
-
<
|
|
4
|
-
<Preview />
|
|
5
|
-
</ClientOnly>
|
|
3
|
+
<Preview />
|
|
6
4
|
<div :class="$style.mainInner">
|
|
7
5
|
<slot></slot>
|
|
8
6
|
</div>
|
|
@@ -24,7 +22,7 @@
|
|
|
24
22
|
|
|
25
23
|
@include bp.below('mobile') {
|
|
26
24
|
--_pMainBase: var(--_bitran_asideWidth);
|
|
27
|
-
font-size:
|
|
25
|
+
font-size: 15px;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
.mainInner {
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
navBookVisible,
|
|
8
8
|
} from '@app/scripts/aside/major/nav';
|
|
9
9
|
|
|
10
|
+
import { detectContentBookId } from '@shared/content/bookId';
|
|
11
|
+
|
|
10
12
|
import NavGlobal from './NavGlobal.vue';
|
|
11
13
|
import NavBook from './NavBook.vue';
|
|
12
14
|
|
|
@@ -23,12 +25,15 @@ asideMajorNav.globalNav ||= (await $fetch('/api/aside/major/nav/global', {
|
|
|
23
25
|
|
|
24
26
|
const checkIfInsideBook = () => {
|
|
25
27
|
if (contentRoute.value) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const bookId = detectContentBookId(
|
|
29
|
+
contentRoute.value.contentId,
|
|
30
|
+
asideMajorNav.booksIds
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (bookId) {
|
|
34
|
+
navBookId.value = bookId;
|
|
35
|
+
insideNavBook.value = true;
|
|
36
|
+
return;
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { ContentFlag } from '@erudit-js/cog/schema';
|
|
3
3
|
import { flagsData } from '@app/scripts/flag';
|
|
4
4
|
|
|
5
|
-
defineProps<{ flags: Record<ContentFlag, boolean
|
|
5
|
+
defineProps<{ flags: Partial<Record<ContentFlag, boolean>> }>();
|
|
6
6
|
|
|
7
7
|
const phrases = Object.values(flagsData).map((data) => data.title);
|
|
8
8
|
const phrase = await usePhrases(...phrases);
|
|
@@ -3,7 +3,7 @@ import eruditConfig from '#erudit/config';
|
|
|
3
3
|
|
|
4
4
|
import AsideOverlayPane from '../utils/AsideOverlayPane.vue';
|
|
5
5
|
|
|
6
|
-
const props = defineProps<{
|
|
6
|
+
const props = defineProps<{ contentId: string }>();
|
|
7
7
|
const phrase = await usePhrases(
|
|
8
8
|
'make_contribution',
|
|
9
9
|
'material_improvement',
|
|
@@ -23,7 +23,7 @@ const issueLink = computed(() => {
|
|
|
23
23
|
const editPageLink = computed(() => {
|
|
24
24
|
const ghRepository = eruditConfig.repository;
|
|
25
25
|
return ghRepository
|
|
26
|
-
? `https://github.com/${ghRepository.name}/tree/${ghRepository.branch}/content/${props.
|
|
26
|
+
? `https://github.com/${ghRepository.name}/tree/${ghRepository.branch}/content/${props.contentId}`
|
|
27
27
|
: null;
|
|
28
28
|
});
|
|
29
29
|
</script>
|
|
@@ -40,7 +40,7 @@ watch(contentData, () => (contributePaneVisible.value = false));
|
|
|
40
40
|
{{ phrase.no_contributors }}
|
|
41
41
|
</section>
|
|
42
42
|
<AsideMinorContribute
|
|
43
|
-
:
|
|
43
|
+
:contentId="contentData.contentId"
|
|
44
44
|
v-model:pane="contributePaneVisible"
|
|
45
45
|
/>
|
|
46
46
|
</AsideMinorPane>
|
|
@@ -18,7 +18,7 @@ watch(topicData, () => (contributePaneVisible.value = false));
|
|
|
18
18
|
<TopicToc />
|
|
19
19
|
<TopicContributors v-if="topicData.contributors" />
|
|
20
20
|
<AsideMinorContribute
|
|
21
|
-
:
|
|
21
|
+
:contentId="topicData.topicId"
|
|
22
22
|
v-model:pane="contributePaneVisible"
|
|
23
23
|
/>
|
|
24
24
|
</AsideMinorPane>
|
|
@@ -27,9 +27,9 @@ onMounted(() => {
|
|
|
27
27
|
watch(
|
|
28
28
|
topicData,
|
|
29
29
|
() => {
|
|
30
|
-
if (previousFullId === topicData.value.
|
|
30
|
+
if (previousFullId === topicData.value.topicId) return;
|
|
31
31
|
|
|
32
|
-
previousFullId = topicData.value.
|
|
32
|
+
previousFullId = topicData.value.topicId;
|
|
33
33
|
showcase.value = [...topicData.value.contributors!]
|
|
34
34
|
.sort(() => 0.5 - Math.random())
|
|
35
35
|
.slice(0, counter.value.showcase);
|
|
@@ -174,12 +174,7 @@ onMounted(() => {
|
|
|
174
174
|
|
|
175
175
|
if (!topicData.value.location || !topicLocation.value) return;
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
stringifyBitranLocation(topicData.value.location) ===
|
|
179
|
-
stringifyBitranLocation(topicLocation.value)
|
|
180
|
-
) {
|
|
181
|
-
enableLiveToc();
|
|
182
|
-
}
|
|
177
|
+
enableLiveToc();
|
|
183
178
|
},
|
|
184
179
|
{ immediate: true },
|
|
185
180
|
);
|
|
@@ -6,6 +6,8 @@ const productName = props.tocItem.productName;
|
|
|
6
6
|
const productIcon = await useBitranElementIcon(productName);
|
|
7
7
|
const productPhrase = await useBitranElementLanguage(productName);
|
|
8
8
|
|
|
9
|
+
const pretty = useFormatText();
|
|
10
|
+
|
|
9
11
|
function tocItemClick(event: MouseEvent): void {
|
|
10
12
|
navigateTo({
|
|
11
13
|
query: {
|
|
@@ -20,7 +22,7 @@ function tocItemClick(event: MouseEvent): void {
|
|
|
20
22
|
|
|
21
23
|
<template>
|
|
22
24
|
<TreeItem
|
|
23
|
-
:label="tocItem.title || productPhrase('_element_title')"
|
|
25
|
+
:label="pretty(tocItem.title || productPhrase('_element_title'))"
|
|
24
26
|
:level="tocItem.level"
|
|
25
27
|
:link="`?element=${tocItem.id}`"
|
|
26
28
|
:svg="productIcon"
|
|
@@ -56,7 +56,7 @@ const isServer = import.meta.server;
|
|
|
56
56
|
<style lang="scss" module>
|
|
57
57
|
@use '$/def/bp';
|
|
58
58
|
|
|
59
|
-
.eruditBitranContainer {
|
|
59
|
+
:global(.bitran-component).eruditBitranContainer {
|
|
60
60
|
padding: var(--_pMainY) var(--_pMainX);
|
|
61
61
|
padding-left: calc(var(--_pMainX) - var(--_bitran_asideWidth));
|
|
62
62
|
|
|
@@ -13,7 +13,7 @@ function getIcon(contextIcon: string) {
|
|
|
13
13
|
|
|
14
14
|
<template>
|
|
15
15
|
<section :class="$style.breadcrumb">
|
|
16
|
-
<template v-for="contextItem of context.slice(0, -1)">
|
|
16
|
+
<template v-for="contextItem of context.slice(0, -1).filter(item => !item.hidden)">
|
|
17
17
|
<Link :to="contextItem.href" :class="$style.breadcrumbItem">
|
|
18
18
|
<MyIcon :name="getIcon(contextItem.icon)" wrapper="span" />
|
|
19
19
|
{{ contextItem.title }}
|
|
@@ -5,7 +5,7 @@ import { buildPreviewData } from '@app/scripts/preview/build';
|
|
|
5
5
|
import { getPreviewDisplayComponent } from '@app/scripts/preview/display';
|
|
6
6
|
import { createPreviewError } from '@app/scripts/preview/data/alert';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { LazyPreviewDisplayAlert } from '#components';
|
|
9
9
|
|
|
10
10
|
const { request } = defineProps<{ request: PreviewRequest }>();
|
|
11
11
|
const height = defineModel<number>('height');
|
|
@@ -35,7 +35,7 @@ const setupDisplay = setTimeout(async () => {
|
|
|
35
35
|
message: error?.message || error,
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
DisplayComponent.value =
|
|
38
|
+
DisplayComponent.value = LazyPreviewDisplayAlert;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
await nextTick();
|
|
@@ -9,7 +9,7 @@ const phrase = await usePhrases('internal_link_warn');
|
|
|
9
9
|
|
|
10
10
|
<template>
|
|
11
11
|
<PreviewDisplay :footer="data.footer">
|
|
12
|
-
<div :class="$style.wrapper">{{ phrase.internal_link_warn }}</div>
|
|
12
|
+
<div :class="$style.wrapper">{{ data.description || phrase.internal_link_warn }}</div>
|
|
13
13
|
</PreviewDisplay>
|
|
14
14
|
</template>
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ const root = await bitranTranspiler.parser.parse(data.bitran.content.biCode);
|
|
|
21
21
|
<BitranContent
|
|
22
22
|
:content="{
|
|
23
23
|
root,
|
|
24
|
-
|
|
24
|
+
renderDataStorage: data.bitran.content.renderDataStorage,
|
|
25
25
|
}"
|
|
26
26
|
:context="data.bitran.context"
|
|
27
27
|
/>
|
|
@@ -88,7 +88,7 @@ export async function useBitranRenderers() {
|
|
|
88
88
|
|
|
89
89
|
export async function useBitranElementRenderer(productName: string) {
|
|
90
90
|
const renderer =
|
|
91
|
-
(await
|
|
91
|
+
(await getRenderers())[productName] ||
|
|
92
92
|
getDefaultBitranRenderers()[productName];
|
|
93
93
|
|
|
94
94
|
if (!renderer)
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
stringifyBitranLocation,
|
|
8
8
|
type BitranLocation,
|
|
9
9
|
} from '@erudit-js/cog/schema';
|
|
10
|
+
|
|
10
11
|
import type { StringBitranContent } from '@erudit/shared/bitran/stringContent';
|
|
11
12
|
|
|
12
13
|
import eruditConfig from '#erudit/config';
|
|
@@ -28,14 +29,37 @@ export async function useBitranContent(
|
|
|
28
29
|
})();
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
const
|
|
32
|
-
nuxtApp.runWithContext(() => prerenderRoutes(
|
|
32
|
+
const contentApiRoute = `/api/bitran/content/${encodeBitranLocation(stringifyBitranLocation(location.value!))}`;
|
|
33
|
+
nuxtApp.runWithContext(() => prerenderRoutes(contentApiRoute));
|
|
33
34
|
|
|
34
35
|
// @ts-ignore
|
|
35
36
|
contentPromise = (async () => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const locationString = encodeBitranLocation(
|
|
38
|
+
stringifyBitranLocation(location.value!),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const payloadKey = `content`;
|
|
42
|
+
const payload =
|
|
43
|
+
(nuxtApp.static.data[payloadKey] ||=
|
|
44
|
+
nuxtApp.payload.data[payloadKey] ||=
|
|
45
|
+
{});
|
|
46
|
+
|
|
47
|
+
let stringContent: StringBitranContent;
|
|
48
|
+
|
|
49
|
+
if (payload.location === locationString) {
|
|
50
|
+
stringContent = payload;
|
|
51
|
+
} else {
|
|
52
|
+
stringContent = await $fetch(contentApiRoute, {
|
|
53
|
+
responseType: 'json',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Clear the payload and set new data
|
|
57
|
+
Object.keys(payload).forEach((key) => delete payload[key]);
|
|
58
|
+
Object.assign(payload, {
|
|
59
|
+
...stringContent,
|
|
60
|
+
location: locationString,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
39
63
|
|
|
40
64
|
const bitranTranspiler = await useBitranTranspiler();
|
|
41
65
|
|
|
@@ -58,7 +82,7 @@ export async function useBitranContent(
|
|
|
58
82
|
|
|
59
83
|
content.value = {
|
|
60
84
|
root,
|
|
61
|
-
|
|
85
|
+
renderDataStorage: stringContent.renderDataStorage,
|
|
62
86
|
};
|
|
63
87
|
|
|
64
88
|
return content;
|
|
@@ -62,17 +62,16 @@ export function useContentPage(contentData: Ref<ContentData>) {
|
|
|
62
62
|
contentData.value.generic.title ||
|
|
63
63
|
contentData.value.generic.contentId.split('/').pop();
|
|
64
64
|
|
|
65
|
-
if (contentData.value.type !== 'book') {
|
|
66
|
-
const bookTitle = contentData.value?.bookTitle;
|
|
67
|
-
title += bookTitle ? ` | ${bookTitle}` : '';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
65
|
if (contentRoute.value!.type === 'topic') {
|
|
71
66
|
const topicPart = contentRoute.value!.topicPart;
|
|
72
|
-
|
|
73
67
|
if (topicPart !== 'article') title += ` | ${phrase[topicPart]}`;
|
|
74
68
|
}
|
|
75
69
|
|
|
70
|
+
if (contentData.value.type !== 'book') {
|
|
71
|
+
const bookTitle = contentData.value?.bookTitle;
|
|
72
|
+
title += bookTitle ? ` | ${bookTitle}` : '';
|
|
73
|
+
}
|
|
74
|
+
|
|
76
75
|
title +=
|
|
77
76
|
' - ' +
|
|
78
77
|
(eruditConfig.seo?.title ||
|
|
@@ -91,7 +90,9 @@ export function useContentPage(contentData: Ref<ContentData>) {
|
|
|
91
90
|
contentData.value.generic?.description;
|
|
92
91
|
|
|
93
92
|
if (customDescription) {
|
|
94
|
-
seo.description.value = customDescription
|
|
93
|
+
seo.description.value = customDescription
|
|
94
|
+
.trim()
|
|
95
|
+
.replace(/\n/g, ' ');
|
|
95
96
|
return;
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import eruditConfig from '#erudit/config';
|
|
2
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
|
+
|
|
3
14
|
let formatFunction: FormatFunction;
|
|
4
15
|
|
|
5
16
|
export function useFormatText() {
|
|
@@ -11,10 +22,8 @@ export function useFormatText() {
|
|
|
11
22
|
return formatFunction;
|
|
12
23
|
}
|
|
13
24
|
|
|
14
|
-
type FormatFunction = (text: string) => string;
|
|
15
|
-
|
|
16
25
|
function createFormatFunction(language?: string): FormatFunction {
|
|
17
|
-
const formatters:
|
|
26
|
+
const formatters: FormatterFunction[] = [];
|
|
18
27
|
|
|
19
28
|
//
|
|
20
29
|
// Em Dashes
|
|
@@ -36,10 +45,11 @@ function createFormatFunction(language?: string): FormatFunction {
|
|
|
36
45
|
}
|
|
37
46
|
})();
|
|
38
47
|
|
|
39
|
-
formatters.push((text) => {
|
|
40
|
-
let open = false;
|
|
48
|
+
formatters.push((text, state) => {
|
|
41
49
|
return text.replaceAll(/"/gm, () => {
|
|
42
|
-
return (
|
|
50
|
+
return (state.quoteOpen = !state.quoteOpen)
|
|
51
|
+
? quoteSymbols[0]
|
|
52
|
+
: quoteSymbols[1];
|
|
43
53
|
});
|
|
44
54
|
});
|
|
45
55
|
}
|
|
@@ -60,10 +70,13 @@ function createFormatFunction(language?: string): FormatFunction {
|
|
|
60
70
|
//
|
|
61
71
|
//
|
|
62
72
|
|
|
63
|
-
function formatText(
|
|
73
|
+
function formatText(
|
|
74
|
+
text: string,
|
|
75
|
+
state: FormatState = defaultFormatState,
|
|
76
|
+
): string {
|
|
64
77
|
if (!text) return text;
|
|
65
78
|
|
|
66
|
-
for (const formatter of formatters) text = formatter(text);
|
|
79
|
+
for (const formatter of formatters) text = formatter(text, state);
|
|
67
80
|
|
|
68
81
|
return text;
|
|
69
82
|
}
|
|
@@ -15,7 +15,6 @@ const functionPhrases: Record<string, Function> = {};
|
|
|
15
15
|
const phraseApiRoute = (phraseId: EruditPhraseId) =>
|
|
16
16
|
`/api/language/phrase/${phraseId}`;
|
|
17
17
|
const functionsApiRoute = '/api/language/functions';
|
|
18
|
-
const phraseIdsApiRoute = '/api/language/phraseIds';
|
|
19
18
|
|
|
20
19
|
export function usePhrases<T extends EruditPhraseId[]>(
|
|
21
20
|
...phraseIds: T
|
|
@@ -26,11 +25,9 @@ export function usePhrases<T extends EruditPhraseId[]>(
|
|
|
26
25
|
nuxt.payload.data[payloadKey] ||=
|
|
27
26
|
{});
|
|
28
27
|
|
|
29
|
-
const prerenderAllPromise = prerenderAllPhrases();
|
|
30
28
|
const prepareFunctionsPromise = prepareFunctions(payload);
|
|
31
29
|
|
|
32
30
|
return (async () => {
|
|
33
|
-
await prerenderAllPromise;
|
|
34
31
|
await prepareFunctionsPromise;
|
|
35
32
|
|
|
36
33
|
payload.strPhrases ||= {};
|
|
@@ -58,19 +55,6 @@ export function usePhrases<T extends EruditPhraseId[]>(
|
|
|
58
55
|
})();
|
|
59
56
|
}
|
|
60
57
|
|
|
61
|
-
async function prerenderAllPhrases() {
|
|
62
|
-
if (import.meta.dev) return;
|
|
63
|
-
|
|
64
|
-
if (import.meta.client) return;
|
|
65
|
-
|
|
66
|
-
const nuxt = useNuxtApp();
|
|
67
|
-
|
|
68
|
-
const phraseIds = await $fetch(phraseIdsApiRoute);
|
|
69
|
-
nuxt.runWithContext(() =>
|
|
70
|
-
prerenderRoutes(phraseIds.map((phraseId) => phraseApiRoute(phraseId))),
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
58
|
async function prepareFunctions(payload: LanguagePayload) {
|
|
75
59
|
if (payload?.strFunctions) return;
|
|
76
60
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
let alreadyPrerendered = false;
|
|
2
|
+
let isPrerendering = false;
|
|
3
|
+
|
|
4
|
+
export default defineNuxtPlugin({
|
|
5
|
+
name: 'erudit-prerender',
|
|
6
|
+
async setup(_nuxt) {
|
|
7
|
+
if (import.meta.dev) {
|
|
8
|
+
return; // Server is available so no need to prerender in dev mode
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (alreadyPrerendered || isPrerendering) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
isPrerendering = true;
|
|
16
|
+
|
|
17
|
+
const routesToPrerender = await $fetch<string[]>('/api/prerender');
|
|
18
|
+
_nuxt.runWithContext(() => prerenderRoutes(routesToPrerender));
|
|
19
|
+
|
|
20
|
+
alreadyPrerendered = true;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { PreviewDataType, type PreviewData } from './data';
|
|
2
|
-
import { PreviewRequestType, type PreviewRequest } from './request';
|
|
3
|
-
|
|
4
|
-
import { buildGenericLink } from './data/genericLink';
|
|
5
|
-
import { buildPageLink } from './data/pageLink';
|
|
6
|
-
import { buildUnique } from './data/unique';
|
|
7
2
|
import { createPreviewError } from './data/alert';
|
|
3
|
+
import { PreviewRequestType, type PreviewRequest } from './request';
|
|
8
4
|
import { PreviewThemeName } from './state';
|
|
9
5
|
|
|
10
|
-
const builders = [
|
|
6
|
+
const builders = [
|
|
7
|
+
async (request: PreviewRequest) =>
|
|
8
|
+
(await import('./data/genericLink')).buildGenericLink(request),
|
|
9
|
+
async (request: PreviewRequest) =>
|
|
10
|
+
(await import('./data/pageLink')).buildPageLink(request),
|
|
11
|
+
async (request: PreviewRequest) =>
|
|
12
|
+
(await import('./data/unique')).buildUnique(request),
|
|
13
|
+
];
|
|
11
14
|
|
|
12
15
|
export async function buildPreviewData(
|
|
13
16
|
request: PreviewRequest,
|
package/globals/content.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BookConfig,
|
|
3
3
|
ContentReferences,
|
|
4
|
+
ContentReferenceSource,
|
|
4
5
|
GroupConfig,
|
|
5
6
|
TopicConfig,
|
|
6
7
|
} from '@erudit-js/cog/schema';
|
|
@@ -20,3 +21,7 @@ export function defineTopic(topic: Partial<TopicConfig>) {
|
|
|
20
21
|
export function defineContentReferences(references: ContentReferences) {
|
|
21
22
|
return references;
|
|
22
23
|
}
|
|
24
|
+
|
|
25
|
+
export function defineContentSource(source: ContentReferenceSource) {
|
|
26
|
+
return source;
|
|
27
|
+
}
|
package/module/imports.ts
CHANGED
|
@@ -27,12 +27,18 @@ export function setupGlobalImports() {
|
|
|
27
27
|
'defineGroup',
|
|
28
28
|
'defineTopic',
|
|
29
29
|
'defineContentReferences',
|
|
30
|
+
'defineContentSource',
|
|
30
31
|
];
|
|
31
32
|
return imports.map((name) => ({
|
|
32
33
|
name,
|
|
33
34
|
from: eruditPath(`globals/content`),
|
|
34
35
|
}));
|
|
35
36
|
})(),
|
|
37
|
+
// Problems Generation
|
|
38
|
+
{
|
|
39
|
+
name: 'defineProblemGenerator',
|
|
40
|
+
from: '@erudit-js/bitran-elements/problem/generator',
|
|
41
|
+
},
|
|
36
42
|
// Helper Asset Path Functions
|
|
37
43
|
...(() => {
|
|
38
44
|
const imports = [
|
package/module/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { logger } from '@erudit/module/logger';
|
|
|
7
7
|
import { setupGlobalImports } from '@erudit/module/imports';
|
|
8
8
|
import { setupBitranTemplates } from './bitran';
|
|
9
9
|
import { setupGlobalPaths } from './paths';
|
|
10
|
+
import { setupProblemGenerators } from './problemGenerators';
|
|
10
11
|
|
|
11
12
|
export default defineNuxtModule({
|
|
12
13
|
meta: { name: 'Erudit', configKey: 'erudit' },
|
|
@@ -18,6 +19,7 @@ export default defineNuxtModule({
|
|
|
18
19
|
|
|
19
20
|
const eruditConfig = await setupEruditConfig(_nuxt);
|
|
20
21
|
await setupBitranTemplates(_nuxt);
|
|
22
|
+
await setupProblemGenerators(_nuxt);
|
|
21
23
|
setupGlobalPaths(_nuxt);
|
|
22
24
|
|
|
23
25
|
if (eruditConfig.site?.baseUrl) {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { addTemplate } from 'nuxt/kit';
|
|
2
|
+
import type { Nuxt } from 'nuxt/schema';
|
|
3
|
+
import { globSync } from 'glob';
|
|
4
|
+
|
|
5
|
+
import { eruditEndNuxtPath, projectPath } from '@erudit/globalPath';
|
|
6
|
+
import { getContentPath } from '@erudit/utils/contentPath';
|
|
7
|
+
|
|
8
|
+
export async function setupProblemGenerators(_nuxt: Nuxt) {
|
|
9
|
+
const templateName = '#erudit/problemGenerators.ts';
|
|
10
|
+
|
|
11
|
+
addTemplate({
|
|
12
|
+
filename: templateName,
|
|
13
|
+
write: true,
|
|
14
|
+
async getContents() {
|
|
15
|
+
const generatorFiles = findGenerators();
|
|
16
|
+
|
|
17
|
+
return `
|
|
18
|
+
export const loaders = {
|
|
19
|
+
${generatorFiles
|
|
20
|
+
.map((file) => {
|
|
21
|
+
const filePath = projectPath('content/' + file);
|
|
22
|
+
const contentPath = getContentPath(
|
|
23
|
+
file,
|
|
24
|
+
projectPath('content'),
|
|
25
|
+
).replace(/\.gen\.(js|ts)$/, '');
|
|
26
|
+
return ` '${contentPath}': async () => (await import('${filePath}')).default,`;
|
|
27
|
+
})
|
|
28
|
+
.join('\n')}
|
|
29
|
+
}
|
|
30
|
+
`.trim();
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const alias = (_nuxt.options.alias ||= {});
|
|
35
|
+
alias['#erudit/problemGenerators'] = eruditEndNuxtPath(
|
|
36
|
+
`.nuxt/${templateName}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function findGenerators() {
|
|
41
|
+
const generatorFiles = globSync('**/*.gen.{js,ts}', {
|
|
42
|
+
cwd: projectPath('content'),
|
|
43
|
+
posix: true,
|
|
44
|
+
});
|
|
45
|
+
return generatorFiles;
|
|
46
|
+
}
|
package/nuxt.config.ts
CHANGED
|
@@ -18,11 +18,17 @@ export default defineNuxtConfig({
|
|
|
18
18
|
'@shared': eruditPath('shared'),
|
|
19
19
|
'@app': eruditPath('app'),
|
|
20
20
|
$: eruditPath('app/styles'),
|
|
21
|
+
//
|
|
22
|
+
'#project': projectPath(),
|
|
23
|
+
'#content': projectPath('content'),
|
|
21
24
|
},
|
|
22
25
|
modules: [eruditPath('module'), 'nuxt-my-icons'],
|
|
23
26
|
myicons: {
|
|
24
27
|
iconsDir: eruditPath('app/assets/icons'),
|
|
25
28
|
},
|
|
29
|
+
features: {
|
|
30
|
+
inlineStyles: false,
|
|
31
|
+
},
|
|
26
32
|
typescript: {
|
|
27
33
|
tsConfig: {
|
|
28
34
|
include: [eruditPath('**/*'), projectPath('**/*')],
|
|
@@ -47,11 +53,6 @@ export default defineNuxtConfig({
|
|
|
47
53
|
projectPath(`contributors/${pattern}`),
|
|
48
54
|
),
|
|
49
55
|
],
|
|
50
|
-
esbuild: {
|
|
51
|
-
options: {
|
|
52
|
-
charset: 'utf8',
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
56
|
nitro: {
|
|
56
57
|
preset: 'github-pages',
|
|
57
58
|
plugins: [eruditPath('server/plugin')],
|
|
@@ -88,6 +89,7 @@ export default defineNuxtConfig({
|
|
|
88
89
|
],
|
|
89
90
|
esbuild: {
|
|
90
91
|
options: {
|
|
92
|
+
charset: 'utf8',
|
|
91
93
|
tsconfigRaw: {
|
|
92
94
|
compilerOptions: {
|
|
93
95
|
experimentalDecorators: true, // Make TypeORM work with Nuxt,
|