@erudit-js/prose 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.
- package/dist/app/default/Inliners.vue +11 -11
- package/dist/app/default/Mix.vue +11 -11
- package/dist/app/default/Text.vue +25 -25
- package/dist/app/shared/Prose.vue +40 -40
- package/dist/app/shared/Render.vue +51 -51
- package/dist/app/shared/block/AsideMenu.vue +44 -44
- package/dist/app/shared/block/AsideMenuButton.vue +51 -53
- package/dist/app/shared/block/AsideMenuCopyLink.vue +40 -40
- package/dist/app/shared/block/AsideMenuSeparator.vue +3 -3
- package/dist/app/shared/block/Block.vue +270 -275
- package/dist/app/shared/inliner/Inliner.vue +11 -11
- package/dist/app/shared/photoswipe/style.css +22 -26
- package/dist/elements/accent/Accent.vue +88 -92
- package/dist/elements/accent/AccentColumnSection.vue +61 -61
- package/dist/elements/accent/AccentRowSections.vue +64 -65
- package/dist/elements/callout/Callout.vue +81 -85
- package/dist/elements/callout/_global.d.ts +15 -15
- package/dist/elements/caption/Caption.vue +44 -47
- package/dist/elements/caption/_global.d.ts +26 -26
- package/dist/elements/details/Details.vue +49 -50
- package/dist/elements/details/_global.d.ts +27 -27
- package/dist/elements/diagram/Diagram.vue +360 -374
- package/dist/elements/diagram/_global.d.ts +19 -19
- package/dist/elements/diagram/core.d.ts +0 -4
- package/dist/elements/diagram/core.js +1 -7
- package/dist/elements/emphasis/Emphasis.vue +25 -25
- package/dist/elements/emphasis/_global.d.ts +18 -18
- package/dist/elements/flex/Flex.vue +36 -38
- package/dist/elements/flex/_global.d.ts +23 -23
- package/dist/elements/gallery/Gallery.vue +56 -56
- package/dist/elements/gallery/_global.d.ts +18 -18
- package/dist/elements/heading/Heading.vue +44 -44
- package/dist/elements/heading/_global.d.ts +42 -45
- package/dist/elements/heading/core.js +7 -14
- package/dist/elements/horizontalLine/HorizontalLine.vue +6 -6
- package/dist/elements/horizontalLine/_global.d.ts +17 -17
- package/dist/elements/image/Image.vue +15 -15
- package/dist/elements/image/ImageElement.vue +80 -80
- package/dist/elements/image/_global.d.ts +18 -18
- package/dist/elements/lineBreak/LineBreak.vue +3 -3
- package/dist/elements/lineBreak/_global.d.ts +18 -18
- package/dist/elements/link/BlockLink.vue +108 -110
- package/dist/elements/link/Link.vue +92 -96
- package/dist/elements/link/dependency/_global.d.ts +47 -47
- package/dist/elements/link/reference/_global.d.ts +49 -49
- package/dist/elements/list/List.vue +58 -65
- package/dist/elements/list/_global.d.ts +50 -50
- package/dist/elements/math/_global.d.ts +72 -72
- package/dist/elements/math/_global.ts +3 -3
- package/dist/elements/math/components/BlockMath.vue +30 -30
- package/dist/elements/math/components/InlinerMath.vue +65 -65
- package/dist/elements/math/components/Katex.vue +88 -89
- package/dist/elements/math/components/MathGroup.vue +41 -41
- package/dist/elements/math/katex.js +17 -6
- package/dist/elements/paragraph/Paragraph.vue +25 -27
- package/dist/elements/paragraph/_global.d.ts +27 -27
- package/dist/elements/problem/_global.d.ts +112 -112
- package/dist/elements/problem/components/Problem.vue +22 -22
- package/dist/elements/problem/components/ProblemButton.vue +20 -21
- package/dist/elements/problem/components/ProblemContainer.vue +8 -8
- package/dist/elements/problem/components/ProblemContent.vue +356 -371
- package/dist/elements/problem/components/ProblemExpander.vue +7 -7
- package/dist/elements/problem/components/ProblemExpanderSection.vue +57 -57
- package/dist/elements/problem/components/ProblemHeader.vue +100 -102
- package/dist/elements/problem/components/Problems.vue +83 -87
- package/dist/elements/problem/components/SubProblem.vue +14 -14
- package/dist/elements/problem/components/expanders/Check.vue +153 -150
- package/dist/elements/problem/components/expanders/Checks.vue +146 -83
- package/dist/elements/problem/components/expanders/DefaultPlusSections.vue +38 -38
- package/dist/elements/problem/components/expanders/Hint.vue +26 -26
- package/dist/elements/problem/core.d.ts +23 -23
- package/dist/elements/problem/problemContent.d.ts +134 -30
- package/dist/elements/problem/problemContent.js +157 -197
- package/dist/elements/problem/problemScript.d.ts +2 -2
- package/dist/elements/problem/problemScript.js +2 -2
- package/dist/elements/problem/rng.d.ts +1 -1
- package/dist/elements/problem/rng.js +1 -1
- package/dist/elements/table/Table.vue +100 -102
- package/dist/elements/table/_global.d.ts +36 -36
- package/dist/elements/video/Video.vue +110 -109
- package/dist/elements/video/_global.d.ts +18 -18
- package/package.json +42 -43
- package/types.d.ts +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</template>
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div class="border-border border-t">
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</div>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { ref, watchEffect } from 'vue';
|
|
3
|
-
import type { AnySchema, ProseElement } from '@jsprose/core';
|
|
4
|
-
|
|
5
|
-
import plusIcon from '../../../app/shared/assets/plus.svg?raw';
|
|
6
|
-
import { useProseContext } from '../../../app/composables/context.js';
|
|
7
|
-
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
8
|
-
import { useContainsAnchor } from '../../../app/composables/anchor.js';
|
|
9
|
-
import Render from '../../../app/shared/Render.vue';
|
|
10
|
-
|
|
11
|
-
const { element } = defineProps<{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}>();
|
|
15
|
-
|
|
16
|
-
const formatText = useFormatText();
|
|
17
|
-
const { EruditIcon } = useProseContext();
|
|
18
|
-
const opened = ref(false);
|
|
19
|
-
const containsAnchor = useContainsAnchor(element);
|
|
20
|
-
|
|
21
|
-
watchEffect(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<template>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ref, watchEffect } from 'vue';
|
|
3
|
+
import type { AnySchema, ProseElement } from '@jsprose/core';
|
|
4
|
+
|
|
5
|
+
import plusIcon from '../../../app/shared/assets/plus.svg?raw';
|
|
6
|
+
import { useProseContext } from '../../../app/composables/context.js';
|
|
7
|
+
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
8
|
+
import { useContainsAnchor } from '../../../app/composables/anchor.js';
|
|
9
|
+
import Render from '../../../app/shared/Render.vue';
|
|
10
|
+
|
|
11
|
+
const { element } = defineProps<{
|
|
12
|
+
title: string;
|
|
13
|
+
element: ProseElement<AnySchema>;
|
|
14
|
+
}>();
|
|
15
|
+
|
|
16
|
+
const formatText = useFormatText();
|
|
17
|
+
const { EruditIcon } = useProseContext();
|
|
18
|
+
const opened = ref(false);
|
|
19
|
+
const containsAnchor = useContainsAnchor(element);
|
|
20
|
+
|
|
21
|
+
watchEffect(() => {
|
|
22
|
+
if (containsAnchor.value) {
|
|
23
|
+
opened.value = true;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<div
|
|
30
|
+
@click="opened = !opened"
|
|
31
|
+
class="group border-border text-text-muted relative flex cursor-pointer
|
|
32
|
+
items-center border-t p-(--proseAsideWidth) font-semibold
|
|
33
|
+
first:border-t-0"
|
|
34
|
+
>
|
|
35
|
+
<div class="flex-1">{{ formatText(title) }}</div>
|
|
36
|
+
<button
|
|
37
|
+
class="group-hocus:bg-border/80 text-text-muted shrink-0 rounded
|
|
38
|
+
bg-transparent p-0.5 transition-[background]"
|
|
39
|
+
>
|
|
40
|
+
<EruditIcon
|
|
41
|
+
:name="plusIcon"
|
|
42
|
+
:class="[
|
|
43
|
+
'micro:text-[26px] text-[22px] transition-[rotate]',
|
|
44
|
+
opened ? 'rotate-45' : '',
|
|
45
|
+
]"
|
|
46
|
+
/>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<Suspense>
|
|
50
|
+
<div
|
|
51
|
+
v-if="opened"
|
|
52
|
+
class="border-border border-t border-dashed py-(--proseAsideWidth)"
|
|
53
|
+
>
|
|
54
|
+
<Render v-for="child of element.children" :element="child" />
|
|
55
|
+
</div>
|
|
56
|
+
</Suspense>
|
|
57
|
+
</template>
|
|
@@ -1,102 +1,100 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { useProseContext } from '../../../app/composables/context.js';
|
|
3
|
-
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
4
|
-
import { useProblemPhrase } from '../composables/phrase.js';
|
|
5
|
-
import type { ProblemAttribute, ProblemInfo, ProblemLevel } from '../shared.js';
|
|
6
|
-
|
|
7
|
-
const { info } = defineProps<{
|
|
8
|
-
|
|
9
|
-
}>();
|
|
10
|
-
|
|
11
|
-
const { EruditIcon } = useProseContext();
|
|
12
|
-
const formatText = useFormatText();
|
|
13
|
-
const phrase = await useProblemPhrase();
|
|
14
|
-
|
|
15
|
-
const attributeIcons: Record<ProblemAttribute, string> = Object.fromEntries(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const levelEmojies: Record<ProblemLevel, string> = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const levelColors: Record<ProblemLevel, string> = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<template>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
</header>
|
|
102
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { useProseContext } from '../../../app/composables/context.js';
|
|
3
|
+
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
4
|
+
import { useProblemPhrase } from '../composables/phrase.js';
|
|
5
|
+
import type { ProblemAttribute, ProblemInfo, ProblemLevel } from '../shared.js';
|
|
6
|
+
|
|
7
|
+
const { info } = defineProps<{
|
|
8
|
+
info: ProblemInfo;
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
const { EruditIcon } = useProseContext();
|
|
12
|
+
const formatText = useFormatText();
|
|
13
|
+
const phrase = await useProblemPhrase();
|
|
14
|
+
|
|
15
|
+
const attributeIcons: Record<ProblemAttribute, string> = Object.fromEntries(
|
|
16
|
+
Object.entries(
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
import.meta.glob('../assets/attributes/*.svg', {
|
|
19
|
+
query: 'raw',
|
|
20
|
+
eager: true,
|
|
21
|
+
import: 'default',
|
|
22
|
+
}),
|
|
23
|
+
).map(([key, value]) => {
|
|
24
|
+
const name = key.split('/').pop()?.replace('.svg', '') ?? key;
|
|
25
|
+
return [name as any, value as string];
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const levelEmojies: Record<ProblemLevel, string> = {
|
|
30
|
+
example: '👀',
|
|
31
|
+
easy: '😀',
|
|
32
|
+
medium: '🤔',
|
|
33
|
+
hard: '🤯',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const levelColors: Record<ProblemLevel, string> = {
|
|
37
|
+
example: 'light-dark(#1c8baf, #2a9ab8)',
|
|
38
|
+
easy: 'light-dark(#73af00, #79b800)',
|
|
39
|
+
medium: 'light-dark(#db9c00, #ffc01e)',
|
|
40
|
+
hard: 'light-dark(#dc2f51, #ff375f)',
|
|
41
|
+
};
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<header
|
|
46
|
+
class="micro:flex-row micro:items-center micro:gap-normal gap-small flex
|
|
47
|
+
flex-col flex-wrap p-(--proseAsideWidth) pb-0"
|
|
48
|
+
>
|
|
49
|
+
<h2 class="text-text-deep text-main-lg flex-1 font-bold">
|
|
50
|
+
{{ formatText(info.title) }}
|
|
51
|
+
</h2>
|
|
52
|
+
<div
|
|
53
|
+
class="micro:[--labelHeight:32px] gap-small micro:justify-start
|
|
54
|
+
micro:flex-row flex flex-row-reverse flex-wrap items-center justify-end
|
|
55
|
+
[--labelHeight:28px]"
|
|
56
|
+
>
|
|
57
|
+
<div
|
|
58
|
+
v-for="attribute of info.attributes.sort()"
|
|
59
|
+
:title="
|
|
60
|
+
typeof attribute === 'string'
|
|
61
|
+
? phrase[`attribute_explain.${attribute}`]
|
|
62
|
+
: attribute.hint
|
|
63
|
+
"
|
|
64
|
+
class="border-border/60 bg-bg-main text-main-xs text-text-muted flex
|
|
65
|
+
h-(--labelHeight) cursor-help items-center gap-1 rounded-xl border
|
|
66
|
+
px-2 shadow shadow-[light-dark(#d9d9d9,#3c3c3c)]"
|
|
67
|
+
>
|
|
68
|
+
<EruditIcon
|
|
69
|
+
v-if="typeof attribute === 'string' || attribute.icon"
|
|
70
|
+
:name="
|
|
71
|
+
typeof attribute === 'string'
|
|
72
|
+
? attributeIcons[attribute]
|
|
73
|
+
: attribute.icon
|
|
74
|
+
"
|
|
75
|
+
class="text-[15px]"
|
|
76
|
+
/>
|
|
77
|
+
<span>
|
|
78
|
+
{{
|
|
79
|
+
typeof attribute === 'string'
|
|
80
|
+
? phrase[`attribute.${attribute}`]
|
|
81
|
+
: attribute.label
|
|
82
|
+
}}
|
|
83
|
+
</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div
|
|
86
|
+
:style="{ '--levelColor': levelColors[info.level] }"
|
|
87
|
+
:title="phrase.level_hint"
|
|
88
|
+
class="text-main-xs flex h-(--labelHeight) cursor-help items-center
|
|
89
|
+
gap-1 rounded-xl border border-(--levelColor)/30 bg-(--levelColor)/10
|
|
90
|
+
px-2 font-semibold text-(--levelColor) shadow
|
|
91
|
+
shadow-(color:--levelColor)/25"
|
|
92
|
+
>
|
|
93
|
+
<div class="text-[15px]">
|
|
94
|
+
{{ levelEmojies[info.level] }}
|
|
95
|
+
</div>
|
|
96
|
+
<div>{{ phrase[`level.${info.level}`] }}</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</header>
|
|
100
|
+
</template>
|
|
@@ -1,87 +1,83 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, watchEffect } from 'vue';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from '@jsprose/core';
|
|
8
|
-
|
|
9
|
-
import { subProblemSchema, type problemsSchema } from '../problems.js';
|
|
10
|
-
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
11
|
-
import { useArrayContainsAnchor } from '../../../app/composables/anchor.js';
|
|
12
|
-
import SubProblem from './SubProblem.vue';
|
|
13
|
-
import Block from '../../../app/shared/block/Block.vue';
|
|
14
|
-
import ProblemContainer from './ProblemContainer.vue';
|
|
15
|
-
import ProblemHeader from './ProblemHeader.vue';
|
|
16
|
-
import Render from '../../../app/shared/Render.vue';
|
|
17
|
-
import ProblemButton from './ProblemButton.vue';
|
|
18
|
-
|
|
19
|
-
const { element } = defineProps<{
|
|
20
|
-
|
|
21
|
-
}>();
|
|
22
|
-
|
|
23
|
-
const formatText = useFormatText();
|
|
24
|
-
|
|
25
|
-
const sharedChildren = element.children.filter(
|
|
26
|
-
|
|
27
|
-
) as ProseElement<BlockSchema>[];
|
|
28
|
-
|
|
29
|
-
const subProblems = element.children.filter((child) =>
|
|
30
|
-
|
|
31
|
-
) as ProseElement<typeof subProblemSchema>[];
|
|
32
|
-
|
|
33
|
-
const activeSubProblemI = ref(0);
|
|
34
|
-
|
|
35
|
-
function getUnlabeledOrdinal(index: number) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const containsAnchorI = useArrayContainsAnchor(subProblems);
|
|
44
|
-
|
|
45
|
-
watchEffect(() => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<template>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
</Suspense>
|
|
85
|
-
</ProblemContainer>
|
|
86
|
-
</Block>
|
|
87
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watchEffect } from 'vue';
|
|
3
|
+
import {
|
|
4
|
+
isProseElement,
|
|
5
|
+
type BlockSchema,
|
|
6
|
+
type ProseElement,
|
|
7
|
+
} from '@jsprose/core';
|
|
8
|
+
|
|
9
|
+
import { subProblemSchema, type problemsSchema } from '../problems.js';
|
|
10
|
+
import { useFormatText } from '../../../app/composables/formatText.js';
|
|
11
|
+
import { useArrayContainsAnchor } from '../../../app/composables/anchor.js';
|
|
12
|
+
import SubProblem from './SubProblem.vue';
|
|
13
|
+
import Block from '../../../app/shared/block/Block.vue';
|
|
14
|
+
import ProblemContainer from './ProblemContainer.vue';
|
|
15
|
+
import ProblemHeader from './ProblemHeader.vue';
|
|
16
|
+
import Render from '../../../app/shared/Render.vue';
|
|
17
|
+
import ProblemButton from './ProblemButton.vue';
|
|
18
|
+
|
|
19
|
+
const { element } = defineProps<{
|
|
20
|
+
element: ProseElement<typeof problemsSchema>;
|
|
21
|
+
}>();
|
|
22
|
+
|
|
23
|
+
const formatText = useFormatText();
|
|
24
|
+
|
|
25
|
+
const sharedChildren = element.children.filter(
|
|
26
|
+
(child) => !isProseElement(child, subProblemSchema),
|
|
27
|
+
) as ProseElement<BlockSchema>[];
|
|
28
|
+
|
|
29
|
+
const subProblems = element.children.filter((child) =>
|
|
30
|
+
isProseElement(child, subProblemSchema),
|
|
31
|
+
) as ProseElement<typeof subProblemSchema>[];
|
|
32
|
+
|
|
33
|
+
const activeSubProblemI = ref(0);
|
|
34
|
+
|
|
35
|
+
function getUnlabeledOrdinal(index: number) {
|
|
36
|
+
let count = 0;
|
|
37
|
+
for (let i = 0; i <= index; i++) {
|
|
38
|
+
if (!subProblems[i].data.label) count++;
|
|
39
|
+
}
|
|
40
|
+
return count;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const containsAnchorI = useArrayContainsAnchor(subProblems);
|
|
44
|
+
|
|
45
|
+
watchEffect(() => {
|
|
46
|
+
if (containsAnchorI.value !== undefined) {
|
|
47
|
+
activeSubProblemI.value = containsAnchorI.value;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<Block :element>
|
|
54
|
+
<ProblemContainer>
|
|
55
|
+
<ProblemHeader :info="element.data" />
|
|
56
|
+
<div v-if="sharedChildren.length" class="pt-(--proseAsideWidth)">
|
|
57
|
+
<Render v-for="sharedChild of sharedChildren" :element="sharedChild" />
|
|
58
|
+
</div>
|
|
59
|
+
<div
|
|
60
|
+
class="gap-small micro:gap-normal border-border micro:*:px-4 flex
|
|
61
|
+
flex-wrap border-b px-(--proseAsideWidth) py-(--proseAsideWidth)"
|
|
62
|
+
>
|
|
63
|
+
<ProblemButton
|
|
64
|
+
v-for="(subProblem, i) of subProblems"
|
|
65
|
+
:active="i === activeSubProblemI"
|
|
66
|
+
@click="activeSubProblemI = i"
|
|
67
|
+
>
|
|
68
|
+
{{
|
|
69
|
+
subProblem.data.label
|
|
70
|
+
? formatText(subProblem.data.label)
|
|
71
|
+
: getUnlabeledOrdinal(i)
|
|
72
|
+
}}
|
|
73
|
+
</ProblemButton>
|
|
74
|
+
</div>
|
|
75
|
+
<Suspense>
|
|
76
|
+
<SubProblem
|
|
77
|
+
:key="activeSubProblemI"
|
|
78
|
+
:element="subProblems[activeSubProblemI]"
|
|
79
|
+
/>
|
|
80
|
+
</Suspense>
|
|
81
|
+
</ProblemContainer>
|
|
82
|
+
</Block>
|
|
83
|
+
</template>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import type { ProseElement } from '@jsprose/core';
|
|
3
|
-
|
|
4
|
-
import type { subProblemSchema } from '../problems.js';
|
|
5
|
-
import ProblemContent from './ProblemContent.vue';
|
|
6
|
-
|
|
7
|
-
const { element } = defineProps<{
|
|
8
|
-
|
|
9
|
-
}>();
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<template>
|
|
13
|
-
|
|
14
|
-
</template>
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { ProseElement } from '@jsprose/core';
|
|
3
|
+
|
|
4
|
+
import type { subProblemSchema } from '../problems.js';
|
|
5
|
+
import ProblemContent from './ProblemContent.vue';
|
|
6
|
+
|
|
7
|
+
const { element } = defineProps<{
|
|
8
|
+
element: ProseElement<typeof subProblemSchema>;
|
|
9
|
+
}>();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<ProblemContent :element :initialElements="element.children" />
|
|
14
|
+
</template>
|