erudit 3.0.0-dev.21 → 3.0.0-dev.23

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 (72) hide show
  1. package/app/assets/icons/cameo-add.svg +3 -3
  2. package/app/assets/icons/diamond.svg +2 -2
  3. package/app/assets/icons/files.svg +5 -0
  4. package/app/assets/icons/list-squared.svg +3 -0
  5. package/app/assets/icons/rocket.svg +1 -0
  6. package/app/components/GroupLikePage.vue +70 -0
  7. package/app/components/QuickLinks.vue +99 -0
  8. package/app/components/aside/major/SiteInfo.vue +2 -2
  9. package/app/components/aside/major/panes/nav/NavBook.vue +1 -1
  10. package/app/components/aside/major/panes/other/ItemTheme.vue +25 -30
  11. package/app/components/index/IndexAvatars.vue +143 -0
  12. package/app/components/main/MainActionButton.vue +3 -1
  13. package/app/components/main/MainBitranContent.vue +13 -0
  14. package/app/components/main/MainDescription.vue +6 -0
  15. package/app/components/main/MainSectionTitle.vue +50 -0
  16. package/app/components/main/MainSourceUsages.vue +119 -0
  17. package/app/components/main/MainSourcesUsage.vue +60 -0
  18. package/app/components/main/MainToc.vue +135 -0
  19. package/app/components/main/content/ContentPopovers.vue +9 -2
  20. package/app/components/main/content/ContentReferences.vue +1 -27
  21. package/app/components/main/content/reference/ReferenceGroup.vue +10 -9
  22. package/app/components/main/content/reference/ReferenceSource.vue +1 -0
  23. package/app/components/main/topic/MainTopic.vue +5 -8
  24. package/app/components/main/topic/MainTopicQuickLinks.vue +24 -0
  25. package/app/components/stats/Stats.vue +21 -0
  26. package/app/components/stats/StatsGroupLike.vue +24 -0
  27. package/app/components/stats/StatsItem.vue +33 -0
  28. package/app/components/stats/StatsItemElement.vue +13 -0
  29. package/app/composables/bitranLocation.ts +2 -3
  30. package/app/composables/contentPage.ts +7 -6
  31. package/app/composables/theme.ts +26 -5
  32. package/app/pages/book/[...bookId].vue +6 -31
  33. package/app/pages/group/[...groupId].vue +5 -41
  34. package/app/pages/index.vue +189 -16
  35. package/app/pages/sponsors.vue +2 -2
  36. package/app/scripts/preview/data/pageLink.ts +4 -3
  37. package/app/scripts/preview/data/unique.ts +6 -6
  38. package/languages/en.ts +7 -1
  39. package/languages/ru.ts +10 -3
  40. package/package.json +4 -4
  41. package/server/api/content/data.ts +33 -11
  42. package/server/api/index/data.ts +46 -0
  43. package/server/plugin/bitran/content.ts +0 -14
  44. package/server/plugin/bitran/location.ts +3 -6
  45. package/server/plugin/build/jobs/content/parse.ts +95 -1
  46. package/server/plugin/build/jobs/content/type/group.ts +0 -21
  47. package/server/plugin/content/context.ts +3 -6
  48. package/server/plugin/db/entities/Group.ts +0 -3
  49. package/server/plugin/db/entities/QuickLink.ts +19 -0
  50. package/server/plugin/db/entities/Stat.ts +13 -0
  51. package/server/plugin/db/setup.ts +4 -0
  52. package/server/plugin/repository/content.ts +3 -3
  53. package/server/plugin/repository/contentToc.ts +90 -0
  54. package/server/plugin/repository/elementStats.ts +80 -0
  55. package/server/plugin/repository/link.ts +20 -0
  56. package/server/plugin/repository/quickLink.ts +36 -0
  57. package/server/plugin/repository/readLink.ts +17 -0
  58. package/server/plugin/repository/reference.ts +78 -0
  59. package/server/plugin/repository/topicCount.ts +19 -0
  60. package/shared/content/data/base.ts +2 -2
  61. package/shared/content/data/groupLike.ts +11 -0
  62. package/shared/content/data/type/book.ts +3 -1
  63. package/shared/content/data/type/group.ts +3 -1
  64. package/shared/content/data/type/topic.ts +3 -1
  65. package/shared/content/reference.ts +18 -0
  66. package/shared/content/toc.ts +35 -0
  67. package/shared/indexData.ts +10 -0
  68. package/shared/link.ts +3 -2
  69. package/shared/quickLink.ts +7 -0
  70. package/shared/stat.ts +23 -0
  71. package/shared/types/language.ts +6 -1
  72. package/utils/normalize.ts +7 -0
@@ -0,0 +1,60 @@
1
+ <script lang="ts" setup>
2
+ import type { ContentSourceUsageSet } from '@shared/content/reference';
3
+ import ReferenceSource from '@app/components/main/content/reference/ReferenceSource.vue';
4
+
5
+ const props = defineProps<{
6
+ usageSet?: ContentSourceUsageSet;
7
+ }>();
8
+
9
+ const count = computed(() => {
10
+ if (!props.usageSet) {
11
+ return 0;
12
+ }
13
+
14
+ return Object.keys(props.usageSet).length;
15
+ });
16
+
17
+ const phrase = await usePhrases('references', 'references_description');
18
+ </script>
19
+
20
+ <template>
21
+ <MainSection v-if="usageSet && count">
22
+ <MainSectionTitle
23
+ icon="link-external"
24
+ :title="phrase.references"
25
+ :count
26
+ />
27
+
28
+ <p :class="$style.description">{{ phrase.references_description }}</p>
29
+
30
+ <ul :class="$style.sources">
31
+ <li v-for="usageItem of usageSet">
32
+ <ReferenceSource :source="usageItem.source">
33
+ <template #after>
34
+ <MainSourceUsages :usages="usageItem.usages" />
35
+ </template>
36
+ </ReferenceSource>
37
+ </li>
38
+ </ul>
39
+ </MainSection>
40
+ </template>
41
+
42
+ <style lang="scss" module>
43
+ .description {
44
+ padding: var(--_pMainY) var(--_pMainX);
45
+ }
46
+
47
+ .sources {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: var(--gap);
51
+ list-style: none;
52
+ padding: var(--_pMainY) var(--_pMainX);
53
+ margin: 0;
54
+
55
+ > li:not(:last-of-type) {
56
+ border-bottom: 1px solid var(--border);
57
+ padding-bottom: var(--gap);
58
+ }
59
+ }
60
+ </style>
@@ -0,0 +1,135 @@
1
+ <script lang="ts" setup>
2
+ import { CONTENT_TYPE_ICON } from '@shared/icons';
3
+ import type { ContentToc, ContentTocItem } from '@shared/content/toc';
4
+ import QuickLinks from '../QuickLinks.vue';
5
+
6
+ defineProps<{ toc: ContentToc }>();
7
+
8
+ const pretty = useFormatText();
9
+ const phrase = await usePhrases('toc', 'topics');
10
+
11
+ function hasBottom(tocItem: ContentTocItem): boolean {
12
+ if (tocItem.type === 'topic') {
13
+ return tocItem.quickLinks.length > 0;
14
+ }
15
+
16
+ if (tocItem.type === 'book' || tocItem.type === 'group') {
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
22
+ </script>
23
+
24
+ <template>
25
+ <MainSection>
26
+ <MainSectionTitle
27
+ icon="list-squared"
28
+ :title="phrase.toc"
29
+ :count="toc.length"
30
+ />
31
+ <ol :class="$style.tocItems">
32
+ <li v-for="tocItem of toc" :class="$style.tocItem">
33
+ <EruditLink :to="tocItem.link" :class="$style.tocItemHeading">
34
+ <MyIcon
35
+ :name="CONTENT_TYPE_ICON[tocItem.type]"
36
+ :class="$style.tocItemIcon"
37
+ />
38
+ <h3>
39
+ {{ pretty(tocItem.title) }}
40
+ </h3>
41
+ <MyIcon name="arrow-left" :class="$style.gotoArrow" />
42
+ </EruditLink>
43
+ <div
44
+ v-if="tocItem.description"
45
+ :class="$style.tocItemDescription"
46
+ >
47
+ {{ pretty(tocItem.description) }}
48
+ </div>
49
+ <div v-if="hasBottom(tocItem)" :class="$style.tocItemBottom">
50
+ <QuickLinks
51
+ v-if="
52
+ tocItem.type === 'topic' &&
53
+ tocItem.quickLinks.length
54
+ "
55
+ :links="tocItem.quickLinks"
56
+ />
57
+ <Stats
58
+ v-if="
59
+ tocItem.type === 'book' || tocItem.type === 'group'
60
+ "
61
+ :stats="[
62
+ {
63
+ type: 'custom',
64
+ icon: 'files',
65
+ label: phrase.topics,
66
+ count: tocItem.topicCount,
67
+ },
68
+ ...tocItem.stats,
69
+ ]"
70
+ :class="$style.tocItemStats"
71
+ />
72
+ </div>
73
+ </li>
74
+ </ol>
75
+ </MainSection>
76
+ </template>
77
+
78
+ <style lang="scss" module>
79
+ .tocItems {
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: var(--gapBig);
83
+ list-style: none;
84
+ padding: var(--_pMainY) var(--_pMainX);
85
+ margin: 0;
86
+ }
87
+
88
+ .tocItem {
89
+ background: light-dark(#f7f7f7, #282828);
90
+ border-radius: 5px;
91
+ border: 1px solid var(--border);
92
+
93
+ .tocItemHeading {
94
+ display: flex;
95
+ align-items: center;
96
+ padding: var(--gap);
97
+ color: inherit;
98
+ text-decoration: none;
99
+
100
+ .tocItemIcon {
101
+ color: var(--textMuted);
102
+ margin-right: calc(var(--gap) - 2px);
103
+ }
104
+
105
+ .gotoArrow {
106
+ color: var(--textDimmed);
107
+ transform: scaleX(-1);
108
+ opacity: 0;
109
+ @include transition(color, opacity, transform);
110
+ }
111
+
112
+ &:hover {
113
+ .gotoArrow {
114
+ color: var(--text);
115
+ opacity: 1;
116
+ transform: scaleX(-1) translateX(-12px);
117
+ }
118
+ }
119
+ }
120
+
121
+ .tocItemDescription {
122
+ padding: 0 var(--gap);
123
+ padding-bottom: var(--gap);
124
+ }
125
+
126
+ .tocItemBottom {
127
+ padding: var(--gap);
128
+ padding-top: 0;
129
+
130
+ .tocItemStats {
131
+ gap: var(--gap);
132
+ }
133
+ }
134
+ }
135
+ </style>
@@ -1,14 +1,14 @@
1
1
  <script lang="ts" setup>
2
2
  import type { ContentFlag } from '@erudit-js/cog/schema';
3
3
 
4
- import type { ContentGenericData } from '@shared/content/data/base';
4
+ import type { ContentGeneric } from '@shared/content/data/base';
5
5
 
6
6
  import ContentPopover from './ContentPopover.vue';
7
7
  import type { PopoverData } from '@shared/popover';
8
8
  import { type MyIconName } from '#my-icons';
9
9
 
10
10
  const props = defineProps<{
11
- generic: ContentGenericData /* TODO: customPopovers[] */;
11
+ generic: ContentGeneric /* TODO: customPopovers[] */;
12
12
  }>();
13
13
 
14
14
  const phrase = await usePhrases(
@@ -79,11 +79,18 @@ const hasPopovers = computed(() => {
79
79
  </template>
80
80
 
81
81
  <style lang="scss" module>
82
+ @use '$/def/bp';
83
+
82
84
  .popovers {
83
85
  display: flex;
84
86
  flex-wrap: wrap;
85
87
  gap: var(--gap);
86
88
  padding: var(--_pMainY) var(--_pMainX);
89
+
90
+ @include bp.below('mobile') {
91
+ gap: var(--gapSmall);
92
+ justify-content: center;
93
+ }
87
94
  }
88
95
 
89
96
  .dependenciesList {
@@ -16,11 +16,7 @@ const phrase = await usePhrases('references', 'references_description');
16
16
  </script>
17
17
 
18
18
  <template>
19
- <h2 :class="$style.heading">
20
- <MyIcon name="link-external" :class="$style.icon" />
21
- <span :class="$style.title">{{ phrase.references }}</span>
22
- <span :class="$style.count">{{ count }}</span>
23
- </h2>
19
+ <MainSectionTitle icon="link-external" :title="phrase.references" :count />
24
20
 
25
21
  <p :class="$style.description">{{ phrase.references_description }}</p>
26
22
 
@@ -30,28 +26,6 @@ const phrase = await usePhrases('references', 'references_description');
30
26
  </template>
31
27
 
32
28
  <style lang="scss" module>
33
- .heading {
34
- display: flex;
35
- align-items: center;
36
- gap: var(--gap);
37
- padding: var(--_pMainY) var(--_pMainX);
38
-
39
- .icon {
40
- font-size: 0.9em;
41
- color: var(--textMuted);
42
- }
43
-
44
- .count {
45
- position: relative;
46
- top: 1px;
47
- font-weight: 550;
48
- font-size: 0.6em;
49
- background: color-mix(in srgb, var(--textDimmed), transparent 65%);
50
- border-radius: 20px;
51
- padding: 2px 10px;
52
- }
53
- }
54
-
55
29
  .description {
56
30
  padding: var(--_pMainY) var(--_pMainX);
57
31
  }
@@ -9,10 +9,16 @@ defineProps<{ group: ContentReferenceGroup }>();
9
9
 
10
10
  <template>
11
11
  <div :class="$style.group">
12
- <ReferenceSource :source="group.source" />
13
- <div :class="$style.references">
14
- <ReferenceItem v-for="reference of group.references" :reference />
15
- </div>
12
+ <ReferenceSource :source="group.source">
13
+ <template #after>
14
+ <div :class="$style.references">
15
+ <ReferenceItem
16
+ v-for="reference of group.references"
17
+ :reference
18
+ />
19
+ </div>
20
+ </template>
21
+ </ReferenceSource>
16
22
  </div>
17
23
  </template>
18
24
 
@@ -29,10 +35,5 @@ defineProps<{ group: ContentReferenceGroup }>();
29
35
  display: flex;
30
36
  flex-direction: column;
31
37
  gap: var(--gap);
32
- margin-left: 34px;
33
-
34
- @include bp.below(mobile) {
35
- margin-left: 0;
36
- }
37
38
  }
38
39
  </style>
@@ -49,6 +49,7 @@ const phrase = await usePhrases('reference_source_featured');
49
49
  <div v-if="source.comment" :class="$style.comment">
50
50
  {{ pretty(source.comment) }}
51
51
  </div>
52
+ <slot name="after"></slot>
52
53
  </div>
53
54
  </div>
54
55
  </template>
@@ -43,6 +43,11 @@ const phrase = await usePhrases('article', 'summary', 'practice');
43
43
  :description="topicData.generic?.description"
44
44
  />
45
45
 
46
+ <MainTopicQuickLinks
47
+ v-if="topicData.quickLinks.length"
48
+ :links="topicData.quickLinks"
49
+ />
50
+
46
51
  <ContentPopovers :generic="topicData.generic" />
47
52
 
48
53
  <MainCameo />
@@ -66,11 +71,3 @@ const phrase = await usePhrases('article', 'summary', 'practice');
66
71
  <AdsBannerBottom />
67
72
  </MainSection>
68
73
  </template>
69
-
70
- <style lang="scss" module>
71
- .foo {
72
- position: relative;
73
- width: 100%;
74
- height: 300px;
75
- }
76
- </style>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type { QuickLinks } from '@erudit/shared/quickLink';
3
+
4
+ defineProps<{ links: QuickLinks }>();
5
+ </script>
6
+
7
+ <template>
8
+ <QuickLinks :links :class="$style.topicQuickLinks" />
9
+ </template>
10
+
11
+ <style lang="scss" module>
12
+ @use '$/def/bp';
13
+
14
+ .topicQuickLinks {
15
+ padding: var(--_pMainY) var(--_pMainX);
16
+ --_erudit_quickLink_bg: var(--bgAside);
17
+
18
+ @include bp.below('mobile') {
19
+ > ul {
20
+ justify-content: center;
21
+ }
22
+ }
23
+ }
24
+ </style>
@@ -0,0 +1,21 @@
1
+ <script lang="ts" setup>
2
+ import type { Stats } from '@shared/stat';
3
+
4
+ defineProps<{ stats: Stats }>();
5
+ </script>
6
+
7
+ <template>
8
+ <section :class="$style.stats">
9
+ <template v-for="stat of stats">
10
+ <StatsItem v-if="stat.type === 'custom'" v-bind:stat />
11
+ <StatsItemElement v-else v-bind:stat />
12
+ </template>
13
+ </section>
14
+ </template>
15
+
16
+ <style lang="scss" module>
17
+ .stats {
18
+ display: flex;
19
+ flex-wrap: wrap;
20
+ }
21
+ </style>
@@ -0,0 +1,24 @@
1
+ <script lang="ts" setup>
2
+ import type { Stats } from '@shared/stat';
3
+
4
+ defineProps<{ stats: Stats }>();
5
+ </script>
6
+
7
+ <template>
8
+ <Stats :stats :class="$style.bookGroupStats" />
9
+ </template>
10
+
11
+ <style lang="scss" module>
12
+ @use '$/def/bp';
13
+
14
+ .bookGroupStats {
15
+ gap: var(--gapBig);
16
+ padding: var(--_pMainY) var(--_pMainX);
17
+ font-size: 1.2em;
18
+
19
+ @include bp.below('mobile') {
20
+ justify-content: center;
21
+ gap: var(--gap);
22
+ }
23
+ }
24
+ </style>
@@ -0,0 +1,33 @@
1
+ <script lang="ts" setup>
2
+ import { isMyIcon, type MyIconName } from '#my-icons';
3
+ import type { CustomStat } from '@shared/stat';
4
+
5
+ defineProps<{ stat: CustomStat }>();
6
+ </script>
7
+
8
+ <template>
9
+ <div :class="$style.statsItem" :title="stat.label">
10
+ <MyIcon v-if="isMyIcon(stat.icon)" :name="stat.icon as MyIconName" />
11
+ <MyRuntimeIcon v-else name="stats-item-icon" :svg="stat.icon" />
12
+ <span :class="$style.statsItemCount">{{ stat.count }}</span>
13
+ </div>
14
+ </template>
15
+
16
+ <style lang="scss" module>
17
+ .statsItem {
18
+ display: flex;
19
+ gap: var(--gapSmall);
20
+ align-items: center;
21
+ color: var(--textMuted);
22
+ cursor: help;
23
+
24
+ .statsItemCount {
25
+ font-weight: 600;
26
+ }
27
+
28
+ [my-icon] {
29
+ font-size: 0.9em;
30
+ color: var(--textDimmed);
31
+ }
32
+ }
33
+ </style>
@@ -0,0 +1,13 @@
1
+ <script lang="ts" setup>
2
+ import type { ElementStat } from '@shared/stat';
3
+
4
+ const props = defineProps<{ stat: ElementStat }>();
5
+
6
+ const icon = await useBitranElementIcon(props.stat.elementName);
7
+ const language = await useBitranElementLanguage(props.stat.elementName);
8
+ const label = language('_element_title');
9
+ </script>
10
+
11
+ <template>
12
+ <StatsItem :stat="{ type: 'custom', icon, label, count: stat.count }" />
13
+ </template>
@@ -1,7 +1,6 @@
1
1
  import { locationFromPath, type BitranLocation } from '@erudit-js/cog/schema';
2
2
 
3
- export function useBitranLocation(): ComputedRef<BitranLocation | undefined> {
3
+ export function useBitranLocation(): ComputedRef<BitranLocation> {
4
4
  const route = useRoute();
5
-
6
- return computed(() => locationFromPath(route.path));
5
+ return computed(() => locationFromPath(route.path)!);
7
6
  }
@@ -1,5 +1,6 @@
1
1
  import eruditConfig from '#erudit/config';
2
2
 
3
+ import { normalizeText } from '@erudit/utils/normalize';
3
4
  import { createOgImageTags, defaultOgImage } from '@app/scripts/og';
4
5
  import type { ContentData } from '@shared/content/data';
5
6
 
@@ -100,18 +101,18 @@ export function useContentPage(contentData: Ref<ContentData>) {
100
101
  contentData.value.generic?.description;
101
102
 
102
103
  if (customDescription) {
103
- seo.description.value = customDescription
104
- .trim()
105
- .replace(/\n/g, ' ');
104
+ seo.description.value = normalizeText(customDescription);
106
105
  return;
107
106
  }
108
107
 
109
108
  if (contentRoute.value!.type === 'topic') {
110
109
  const phraseFunc =
111
110
  phrase[`seo_${contentRoute.value!.topicPart}_description`];
112
- seo.description.value = phraseFunc(
113
- contentData.value.generic?.seo?.title ||
114
- contentData.value.generic.title!,
111
+ seo.description.value = normalizeText(
112
+ phraseFunc(
113
+ contentData.value.generic?.seo?.title ||
114
+ contentData.value.generic.title!,
115
+ ),
115
116
  );
116
117
  return;
117
118
  }
@@ -3,12 +3,32 @@ const themes = ['auto', 'light', 'dark'] as const;
3
3
  export type Theme = (typeof themes)[number];
4
4
  export type BinaryTheme = 'light' | 'dark';
5
5
 
6
+ const _theme = ref<Theme>();
7
+
6
8
  export function useTheme() {
7
- const theme = useState<Theme>('theme', () => {
8
- return localStorage.getItem('theme') ?? ('auto' as any);
9
- });
9
+ if (import.meta.server) {
10
+ throw new Error(`Calling 'useTheme' on server side is prohibited!`);
11
+ }
12
+
13
+ function setTheme(newTheme: Theme) {
14
+ localStorage.setItem('theme', newTheme);
15
+ _theme.value = newTheme;
16
+ }
17
+
18
+ const localStorageTheme = localStorage.getItem('theme');
19
+
20
+ if (themes.includes(localStorageTheme as any)) {
21
+ setTheme(localStorageTheme as Theme);
22
+ } else {
23
+ console.warn(
24
+ `Failed to get correct theme value from Local Storage!\nRetrieved "${localStorageTheme}"!`,
25
+ );
26
+ setTheme('auto');
27
+ }
28
+
29
+ const theme = computed<Theme>(() => _theme.value!);
10
30
 
11
- const binaryTheme = computed(() => {
31
+ const binaryTheme = computed<BinaryTheme>(() => {
12
32
  return theme.value === 'auto'
13
33
  ? window.matchMedia('(prefers-color-scheme: dark)').matches
14
34
  ? 'dark'
@@ -17,8 +37,9 @@ export function useTheme() {
17
37
  });
18
38
 
19
39
  const cycle = () => {
20
- theme.value =
40
+ const newTheme =
21
41
  themes[(themes.indexOf(theme.value) + 1) % themes.length]!;
42
+ setTheme(newTheme);
22
43
  };
23
44
 
24
45
  return {
@@ -1,10 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import type { ContentBookData } from '@erudit/shared/content/data/type/book';
3
- import type { MyIconName } from '#my-icons';
4
-
5
- import ContentBreadcrumb from '@app/components/main/content/ContentBreadcrumb.vue';
6
- import ContentDecoration from '@app/components/main/content/ContentDecoration.vue';
7
- import ContentPopovers from '@app/components/main/content/ContentPopovers.vue';
2
+ import type { ContentBookData } from '@shared/content/data/type/book';
8
3
 
9
4
  const bookData = await useContentData<ContentBookData>();
10
5
  await useContentPage(bookData);
@@ -13,30 +8,10 @@ const phrase = await usePhrases('book');
13
8
  </script>
14
9
 
15
10
  <template>
16
- <ContentDecoration
17
- v-if="bookData.generic.decoration"
18
- :decoration="bookData.generic.decoration"
11
+ <GroupLikePage
12
+ icon="outline/book"
13
+ :contentLabel="phrase.book"
14
+ :generic="bookData.generic"
15
+ :groupLike="bookData.groupLike"
19
16
  />
20
-
21
- <ContentBreadcrumb :context="bookData.generic.context" />
22
-
23
- <MainTitle
24
- :title="
25
- bookData.generic?.title ||
26
- bookData.generic.contentId.split('/').pop()!
27
- "
28
- :icon="<MyIconName>'outline/book'"
29
- :hint="phrase.book"
30
- />
31
-
32
- <MainDescription
33
- v-if="bookData.generic?.description"
34
- :description="bookData.generic?.description"
35
- />
36
-
37
- <ContentPopovers :generic="bookData.generic" />
38
-
39
- <!-- Counters, fancy "GO LEARN" button and etc. -->
40
-
41
- <div style="clear: both"></div>
42
17
  </template>
@@ -1,15 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import { type BitranLocation } from '@erudit-js/cog/schema';
3
- import eruditConfig from '#erudit/config';
4
-
5
2
  import { type ContentGroupData } from '@shared/content/data/type/group';
6
- import { locationIcon } from '@erudit/shared/icons';
7
-
8
- import ContentBreadcrumb from '@app/components/main/content/ContentBreadcrumb.vue';
9
- import ContentDecoration from '@app/components/main/content/ContentDecoration.vue';
10
- import ContentPopovers from '@app/components/main/content/ContentPopovers.vue';
11
-
12
- const location = useBitranLocation() as Ref<BitranLocation>;
13
3
 
14
4
  const groupData = await useContentData<ContentGroupData>();
15
5
  await useContentPage(groupData);
@@ -18,36 +8,10 @@ const phrase = await usePhrases('group');
18
8
  </script>
19
9
 
20
10
  <template>
21
- <ContentDecoration
22
- v-if="groupData.generic.decoration"
23
- :decoration="groupData.generic.decoration"
11
+ <GroupLikePage
12
+ icon="folder-open"
13
+ :contentLabel="phrase.group"
14
+ :generic="groupData.generic"
15
+ :groupLike="groupData.groupLike"
24
16
  />
25
-
26
- <ContentBreadcrumb :context="groupData.generic.context" />
27
-
28
- <MainTitle
29
- :title="
30
- groupData.generic?.title ||
31
- groupData.generic.contentId.split('/').pop()!
32
- "
33
- :icon="locationIcon(location!)"
34
- :hint="phrase.group"
35
- />
36
-
37
- <MainDescription
38
- v-if="groupData.generic?.description"
39
- :description="groupData.generic?.description"
40
- />
41
-
42
- <ContentPopovers :generic="groupData.generic" />
43
-
44
- <MainCameo />
45
-
46
- <div style="clear: both"></div>
47
-
48
- <MainBitranContent :location />
49
-
50
- <MainSection v-if="adsAllowed() && eruditConfig.ads?.bottom">
51
- <AdsBannerBottom />
52
- </MainSection>
53
17
  </template>