@erudit-js/prose 4.0.0 → 4.1.0

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 (129) hide show
  1. package/dist/app/composables/context.d.ts +6 -1
  2. package/dist/app/default/Inliners.vue +11 -11
  3. package/dist/app/default/Mix.vue +11 -11
  4. package/dist/app/default/Text.vue +25 -25
  5. package/dist/app/language/element.d.ts +1 -1
  6. package/dist/app/shared/Prose.vue +40 -40
  7. package/dist/app/shared/Render.vue +51 -51
  8. package/dist/app/shared/assets/block.svg +2 -2
  9. package/dist/app/shared/assets/check.svg +2 -2
  10. package/dist/app/shared/assets/inliner.svg +2 -2
  11. package/dist/app/shared/assets/plus.svg +2 -2
  12. package/dist/app/shared/block/AsideMenu.vue +44 -44
  13. package/dist/app/shared/block/AsideMenuButton.vue +51 -51
  14. package/dist/app/shared/block/AsideMenuCopyLink.vue +40 -40
  15. package/dist/app/shared/block/AsideMenuSeparator.vue +3 -3
  16. package/dist/app/shared/block/Block.vue +270 -270
  17. package/dist/app/shared/inliner/Inliner.vue +11 -11
  18. package/dist/app/shared/photoswipe/style.css +22 -22
  19. package/dist/elements/accent/Accent.vue +89 -88
  20. package/dist/elements/accent/AccentColumnSection.vue +61 -61
  21. package/dist/elements/accent/AccentRowSections.vue +64 -64
  22. package/dist/elements/callout/Callout.vue +81 -81
  23. package/dist/elements/callout/_global.d.ts +15 -15
  24. package/dist/elements/caption/Caption.vue +44 -44
  25. package/dist/elements/caption/_global.d.ts +26 -26
  26. package/dist/elements/details/Details.vue +49 -49
  27. package/dist/elements/details/_global.d.ts +27 -27
  28. package/dist/elements/details/icon.svg +2 -2
  29. package/dist/elements/diagram/Diagram.vue +356 -360
  30. package/dist/elements/diagram/_global.d.ts +19 -19
  31. package/dist/elements/emphasis/Emphasis.vue +25 -25
  32. package/dist/elements/emphasis/_global.d.ts +18 -18
  33. package/dist/elements/flex/Flex.vue +36 -36
  34. package/dist/elements/flex/_global.d.ts +23 -23
  35. package/dist/elements/gallery/Gallery.vue +56 -56
  36. package/dist/elements/gallery/_global.d.ts +18 -18
  37. package/dist/elements/heading/Heading.vue +44 -44
  38. package/dist/elements/heading/_global.d.ts +42 -42
  39. package/dist/elements/heading/icon.svg +2 -2
  40. package/dist/elements/horizontalLine/HorizontalLine.vue +6 -6
  41. package/dist/elements/horizontalLine/_global.d.ts +17 -17
  42. package/dist/elements/image/Image.vue +15 -15
  43. package/dist/elements/image/ImageElement.vue +80 -80
  44. package/dist/elements/image/_global.d.ts +18 -18
  45. package/dist/elements/lineBreak/LineBreak.vue +3 -3
  46. package/dist/elements/lineBreak/_global.d.ts +18 -18
  47. package/dist/elements/link/BlockLink.vue +159 -108
  48. package/dist/elements/link/Link.vue +119 -92
  49. package/dist/elements/link/core.js +1 -1
  50. package/dist/elements/link/dependency/_global.d.ts +47 -47
  51. package/dist/elements/link/dependency/app.d.ts +2 -2
  52. package/dist/elements/link/dependency/core.d.ts +12 -18
  53. package/dist/elements/link/dependency/core.js +1 -17
  54. package/dist/elements/link/reference/_global.d.ts +49 -49
  55. package/dist/elements/link/reference/languages/en.d.ts +2 -3
  56. package/dist/elements/link/reference/languages/en.js +5 -1
  57. package/dist/elements/link/reference/languages/ru.d.ts +2 -3
  58. package/dist/elements/link/reference/languages/ru.js +5 -1
  59. package/dist/elements/link/reference/phrases.d.ts +5 -0
  60. package/dist/elements/link/reference/phrases.js +1 -0
  61. package/dist/elements/link/step.d.ts +16 -0
  62. package/dist/elements/link/step.js +36 -0
  63. package/dist/elements/link/storage.d.ts +9 -5
  64. package/dist/elements/link/storage.js +4 -4
  65. package/dist/elements/list/List.vue +58 -58
  66. package/dist/elements/list/_global.d.ts +50 -50
  67. package/dist/elements/math/_global.d.ts +79 -72
  68. package/dist/elements/math/_global.ts +3 -3
  69. package/dist/elements/math/block.d.ts +2 -0
  70. package/dist/elements/math/block.js +42 -29
  71. package/dist/elements/math/components/BlockMath.vue +30 -30
  72. package/dist/elements/math/components/InlinerMath.vue +65 -65
  73. package/dist/elements/math/components/Katex.vue +88 -88
  74. package/dist/elements/math/components/MathGroup.vue +58 -41
  75. package/dist/elements/paragraph/Paragraph.vue +25 -25
  76. package/dist/elements/paragraph/_global.d.ts +27 -27
  77. package/dist/elements/paragraph/icon.svg +3 -3
  78. package/dist/elements/problem/_global.d.ts +257 -112
  79. package/dist/elements/problem/app.d.ts +7 -7
  80. package/dist/elements/problem/app.js +13 -12
  81. package/dist/elements/problem/assets/actions/answer.svg +2 -2
  82. package/dist/elements/problem/assets/actions/check.svg +2 -2
  83. package/dist/elements/problem/assets/actions/generate.svg +2 -2
  84. package/dist/elements/problem/assets/actions/hint.svg +2 -2
  85. package/dist/elements/problem/assets/actions/note.svg +2 -2
  86. package/dist/elements/problem/assets/actions/solution.svg +2 -2
  87. package/dist/elements/problem/assets/icon.svg +2 -2
  88. package/dist/elements/problem/components/Problem.vue +22 -22
  89. package/dist/elements/problem/components/ProblemButton.vue +20 -20
  90. package/dist/elements/problem/components/ProblemButtonGenerate.vue +96 -0
  91. package/dist/elements/problem/components/ProblemContainer.vue +8 -8
  92. package/dist/elements/problem/components/ProblemContent.vue +266 -356
  93. package/dist/elements/problem/components/ProblemExpander.vue +7 -7
  94. package/dist/elements/problem/components/ProblemExpanderSection.vue +57 -57
  95. package/dist/elements/problem/components/ProblemHeader.vue +100 -100
  96. package/dist/elements/problem/components/Problems.vue +83 -83
  97. package/dist/elements/problem/components/SubProblem.vue +14 -14
  98. package/dist/elements/problem/components/expanders/Check.vue +200 -153
  99. package/dist/elements/problem/components/expanders/Checks.vue +146 -146
  100. package/dist/elements/problem/components/expanders/DefaultPlusSections.vue +36 -38
  101. package/dist/elements/problem/components/expanders/Hint.vue +26 -26
  102. package/dist/elements/problem/core.d.ts +55 -28
  103. package/dist/elements/problem/core.js +2 -1
  104. package/dist/elements/problem/languages/{en.d.ts → problem/en.d.ts} +1 -1
  105. package/dist/elements/problem/languages/problem/en.js +6 -0
  106. package/dist/elements/problem/languages/{ru.d.ts → problem/ru.d.ts} +1 -1
  107. package/dist/elements/problem/languages/problem/ru.js +6 -0
  108. package/dist/elements/problem/languages/problems/en.d.ts +3 -0
  109. package/dist/elements/problem/languages/problems/en.js +6 -0
  110. package/dist/elements/problem/languages/problems/ru.d.ts +3 -0
  111. package/dist/elements/problem/languages/problems/ru.js +6 -0
  112. package/dist/elements/problem/languages/shared/en.d.ts +3 -0
  113. package/dist/elements/problem/languages/{en.js → shared/en.js} +12 -3
  114. package/dist/elements/problem/languages/shared/ru.d.ts +3 -0
  115. package/dist/elements/problem/languages/{ru.js → shared/ru.js} +12 -3
  116. package/dist/elements/problem/phrases.d.ts +4 -0
  117. package/dist/elements/problem/problemCheck.d.ts +166 -0
  118. package/dist/elements/problem/problemCheck.js +203 -0
  119. package/dist/elements/problem/problemContent.d.ts +2 -120
  120. package/dist/elements/problem/problemContent.js +2 -127
  121. package/dist/elements/problem/problemScript.d.ts +6 -1
  122. package/dist/elements/table/Table.vue +100 -100
  123. package/dist/elements/table/_global.d.ts +36 -36
  124. package/dist/elements/video/Video.vue +110 -110
  125. package/dist/elements/video/_global.d.ts +18 -18
  126. package/dist/resolve.d.ts +2 -1
  127. package/dist/resolve.js +8 -5
  128. package/package.json +4 -4
  129. package/types.d.ts +4 -4
@@ -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
- 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
+ <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,100 +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
- 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
+ <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,83 +1,83 @@
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
+ <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
- element: ProseElement<typeof subProblemSchema>;
9
- }>();
10
- </script>
11
-
12
- <template>
13
- <ProblemContent :element :initialElements="element.children" />
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>