@eventcatalog/core 2.18.7 → 2.19.1

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 (29) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-7GHQF4IY.js → chunk-BKWJZFAQ.js} +1 -1
  6. package/dist/{chunk-3B32CY7F.js → chunk-G3WSEVOS.js} +1 -1
  7. package/dist/{chunk-KIJRG7DY.js → chunk-HICY5YZU.js} +1 -1
  8. package/dist/constants.cjs +1 -1
  9. package/dist/constants.js +1 -1
  10. package/dist/eventcatalog.cjs +1 -1
  11. package/dist/eventcatalog.js +3 -3
  12. package/eventcatalog/package-lock.json +1074 -142
  13. package/eventcatalog/package.json +5 -4
  14. package/eventcatalog/src/components/MDX/Tabs/Tabs.astro +7 -3
  15. package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +3 -2
  16. package/eventcatalog/src/components/SideBars/DomainSideBar.astro +4 -2
  17. package/eventcatalog/src/components/SideBars/MessageSideBar.astro +4 -2
  18. package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +4 -2
  19. package/eventcatalog/src/content/config.ts +15 -1
  20. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +2 -2
  21. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +2 -2
  22. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +232 -0
  23. package/eventcatalog/src/pages/docs/[type]/[id]/language.astro +19 -60
  24. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +2 -2
  25. package/eventcatalog/src/pages/visualiser/context-map/index.astro +2 -2
  26. package/eventcatalog/src/utils/collections/changelogs.ts +1 -1
  27. package/eventcatalog/src/utils/collections/owners.ts +43 -0
  28. package/eventcatalog/src/utils/collections/util.ts +31 -23
  29. package/package.json +6 -5
@@ -18,9 +18,9 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@astrojs/markdown-remark": "^6.0.1",
21
- "@astrojs/mdx": "^4.0.2",
22
- "@astrojs/react": "^4.1.0",
23
- "@astrojs/tailwind": "^5.1.3",
21
+ "@astrojs/mdx": "^4.0.5",
22
+ "@astrojs/react": "^4.1.3",
23
+ "@astrojs/tailwind": "^5.1.4",
24
24
  "@asyncapi/avro-schema-parser": "^3.0.24",
25
25
  "@asyncapi/parser": "^3.4.0",
26
26
  "@asyncapi/react-component": "^2.4.3",
@@ -32,7 +32,7 @@
32
32
  "@tailwindcss/typography": "^0.5.13",
33
33
  "@tanstack/react-table": "^8.17.3",
34
34
  "@xyflow/react": "^12.3.6",
35
- "astro": "^5.0.5",
35
+ "astro": "^5.1.5",
36
36
  "astro-expressive-code": "^0.38.3",
37
37
  "astro-pagefind": "^1.7.0",
38
38
  "astro-seo": "^0.8.4",
@@ -44,6 +44,7 @@
44
44
  "lodash.debounce": "^4.0.8",
45
45
  "lodash.merge": "4.6.2",
46
46
  "lucide-react": "^0.453.0",
47
+ "marked": "^15.0.6",
47
48
  "mermaid": "^11.4.1",
48
49
  "prismjs": "^1.29.0",
49
50
  "rapidoc": "^9.3.4",
@@ -93,8 +93,12 @@ const tabsId = Math.random().toString(36).substring(2, 9);
93
93
  });
94
94
  }
95
95
 
96
- // Initialize all tab containers
97
- document.querySelectorAll('[data-tabs-container]').forEach((container: Element) => {
98
- initTabs(container as HTMLElement);
96
+ // We use `ViewTransitions`
97
+ // Whenever happens a navigation, from view transitions or native to the browser, init the tabs.
98
+ document.addEventListener('astro:page-load', () => {
99
+ // Initialize all tab containers
100
+ document.querySelectorAll('[data-tabs-container]').forEach((container: Element) => {
101
+ initTabs(container as HTMLElement);
102
+ });
99
103
  });
100
104
  </script>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { getEntry, type CollectionEntry } from 'astro:content';
2
+ import type { CollectionEntry } from 'astro:content';
3
3
  import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import ProtocolList from '@components/Lists/ProtocolList';
5
5
  import OwnersList from '@components/Lists/OwnersList';
@@ -7,6 +7,7 @@ import VersionList from '@components/Lists/VersionList.astro';
7
7
  import { buildUrl } from '@utils/url-builder';
8
8
  import { ScrollText } from 'lucide-react';
9
9
  import RepositoryList from '@components/Lists/RepositoryList.astro';
10
+ import { getOwner } from '@utils/collections/owners';
10
11
 
11
12
  interface Props {
12
13
  channel: CollectionEntry<'channels'>;
@@ -15,7 +16,7 @@ interface Props {
15
16
  const { channel } = Astro.props;
16
17
 
17
18
  const ownersRaw = channel.data?.owners || [];
18
- const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
19
+ const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
19
20
  const filteredOwners = owners.filter((o) => o !== undefined);
20
21
 
21
22
  const channelParameters: Record<string, { enum?: string[]; description?: string }> = channel.data.parameters || {};
@@ -4,9 +4,11 @@ import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import RepositoryList from '@components/Lists/RepositoryList.astro';
5
5
  import VersionList from '@components/Lists/VersionList.astro';
6
6
  import { getUbiquitousLanguage } from '@utils/collections/domains';
7
+ import { getOwner } from '@utils/collections/owners';
7
8
  import { buildUrl } from '@utils/url-builder';
8
- import { getEntry, type CollectionEntry } from 'astro:content';
9
+ import type { CollectionEntry } from 'astro:content';
9
10
  import { ScrollText, Workflow } from 'lucide-react';
11
+
10
12
  interface Props {
11
13
  domain: CollectionEntry<'domains'>;
12
14
  }
@@ -20,7 +22,7 @@ const hasUbiquitousLanguage = ubiquitousLanguage.length > 0;
20
22
  const ubiquitousLanguageDictionary = hasUbiquitousLanguage ? ubiquitousLanguage[0].data.dictionary : [];
21
23
 
22
24
  const ownersRaw = domain.data?.owners || [];
23
- const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
25
+ const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
24
26
  const filteredOwners = owners.filter((o) => o !== undefined);
25
27
 
26
28
  const serviceList = services.map((p) => ({
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { getEntry, type CollectionEntry } from 'astro:content';
2
+ import type { CollectionEntry } from 'astro:content';
3
3
  import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import OwnersList from '@components/Lists/OwnersList';
5
5
  import type { CollectionMessageTypes } from '@types';
@@ -8,6 +8,8 @@ import VersionList from '@components/Lists/VersionList.astro';
8
8
  import { buildUrl } from '@utils/url-builder';
9
9
  import { FileDownIcon, ScrollText, Workflow } from 'lucide-react';
10
10
  import RepositoryList from '@components/Lists/RepositoryList.astro';
11
+ import { getOwner } from '@utils/collections/owners';
12
+
11
13
  interface Props {
12
14
  message: CollectionEntry<CollectionMessageTypes>;
13
15
  }
@@ -19,7 +21,7 @@ const consumers = (message.data.consumers as CollectionEntry<'services'>[]) || [
19
21
  const channels = (message.data.messageChannels as CollectionEntry<'channels'>[]) || [];
20
22
 
21
23
  const ownersRaw = message.data?.owners || [];
22
- const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
24
+ const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
23
25
  const filteredOwners = owners.filter((o) => o !== undefined);
24
26
 
25
27
  const producerList = producers.map((p) => ({
@@ -5,9 +5,11 @@ import RepositoryList from '@components/Lists/RepositoryList.astro';
5
5
  import SpecificationsList from '@components/Lists/SpecificationsList.astro';
6
6
  import VersionList from '@components/Lists/VersionList.astro';
7
7
  import { buildUrl } from '@utils/url-builder';
8
- import { getEntry, type CollectionEntry } from 'astro:content';
8
+ import { getOwner } from '@utils/collections/owners';
9
+ import type { CollectionEntry } from 'astro:content';
9
10
  import { ScrollText, Workflow, FileDownIcon, Code, Link } from 'lucide-react';
10
11
  import { join } from 'node:path';
12
+
11
13
  interface Props {
12
14
  service: CollectionEntry<'services'>;
13
15
  }
@@ -20,7 +22,7 @@ const sends = (service.data.sends as CollectionEntry<'events'>[]) || [];
20
22
  const receives = (service.data.receives as CollectionEntry<'events'>[]) || [];
21
23
 
22
24
  const ownersRaw = service.data?.owners || [];
23
- const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
25
+ const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
24
26
  const filteredOwners = owners.filter((o) => o !== undefined);
25
27
 
26
28
  const sendsList = sends.map((p) => ({
@@ -47,7 +47,21 @@ const changelogs = defineCollection({
47
47
  });
48
48
 
49
49
  // Create a union type for owners
50
- const ownerReference = z.union([reference('users'), reference('teams')]);
50
+ const ownerReference = z
51
+ .union([
52
+ // The ID of the user or team
53
+ z.string(),
54
+ // The full object with the ID and collection (keep compatibility with `reference`)
55
+ z.object({
56
+ id: z.string(),
57
+ collection: z.enum(['users', 'teams']),
58
+ }),
59
+ ])
60
+ .transform(
61
+ // This transformation is needed to keep compatibility with `reference`.
62
+ // The utilities `getTeams` and `getUsers` rely on this transformation.
63
+ (lookup) => ({ id: typeof lookup === 'string' ? lookup : lookup.id })
64
+ );
51
65
 
52
66
  const baseSchema = z.object({
53
67
  id: z.string(),
@@ -11,7 +11,7 @@ import { buildUrl } from '@utils/url-builder';
11
11
  import { getVersions, getPreviousVersion } from '@utils/collections/util';
12
12
  import { getDiffsForCurrentAndPreviousVersion } from '@utils/collections/file-diffs';
13
13
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
14
- import { ViewTransitions } from 'astro:transitions';
14
+ import { ClientRouter } from 'astro:transitions';
15
15
 
16
16
  export async function getStaticPaths() {
17
17
  const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
@@ -222,5 +222,5 @@ const pages = [
222
222
  </div>
223
223
  <Footer />
224
224
  </main>
225
- <ViewTransitions />
225
+ <ClientRouter />
226
226
  </VerticalSideBarLayout>
@@ -18,7 +18,7 @@ import type { PageTypes } from '@types';
18
18
  import { buildUrl } from '@utils/url-builder';
19
19
  import { getFlows } from '@utils/collections/flows';
20
20
  import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
21
- import { ViewTransitions } from 'astro:transitions';
21
+ import { ClientRouter } from 'astro:transitions';
22
22
  import { ArrowsRightLeftIcon } from '@heroicons/react/20/solid';
23
23
 
24
24
  import config from '@config';
@@ -225,7 +225,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
225
225
  {props?.collection === 'channels' && <ChannelSideBar channel={props} />}
226
226
  </aside>
227
227
  </div>
228
- <ViewTransitions />
228
+ <ClientRouter />
229
229
  </main>
230
230
 
231
231
  <style is:global>
@@ -0,0 +1,232 @@
1
+ ---
2
+ import RectangleGroupIcon from '@heroicons/react/24/outline/RectangleGroupIcon';
3
+ import Footer from '@layouts/Footer.astro';
4
+ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
5
+ import { getDomains, getUbiquitousLanguage } from '@utils/collections/domains';
6
+ import { buildUrl } from '@utils/url-builder';
7
+ import { ClientRouter } from 'astro:transitions';
8
+ import { marked } from 'marked';
9
+
10
+ export async function getStaticPaths() {
11
+ const domains = await getDomains({ getAllVersions: false });
12
+
13
+ const pages = await domains.reduce<Promise<any[]>>(async (acc, domain) => {
14
+ const accumulator = await acc;
15
+ const ubiquitousLanguages = await getUbiquitousLanguage(domain);
16
+
17
+ if (ubiquitousLanguages.length === 0) {
18
+ return accumulator;
19
+ }
20
+
21
+ const dictionary = ubiquitousLanguages[0].data.dictionary;
22
+
23
+ if (!dictionary) {
24
+ return accumulator;
25
+ }
26
+
27
+ return [
28
+ ...accumulator,
29
+ ...dictionary.map((item) => ({
30
+ params: {
31
+ type: domain.collection,
32
+ id: domain.data.id,
33
+ dictionaryId: item.id,
34
+ },
35
+ props: {
36
+ type: domain.collection,
37
+ domainId: domain.data.id,
38
+ domain: domain.data,
39
+ ubiquitousLanguage: item,
40
+ ...item,
41
+ },
42
+ })),
43
+ ];
44
+ }, Promise.resolve([]));
45
+
46
+ return pages;
47
+ }
48
+
49
+ const props = Astro.props;
50
+ const { ubiquitousLanguage } = props;
51
+ const pageTitle = `${props.type} | ${ubiquitousLanguage.name}`.replace(/^\w/, (c) => c.toUpperCase());
52
+
53
+ marked.setOptions({
54
+ breaks: true,
55
+ gfm: true,
56
+ });
57
+
58
+ const badges = [
59
+ {
60
+ backgroundColor: 'yellow',
61
+ textColor: 'yellow',
62
+ content: props.domain.name,
63
+ icon: RectangleGroupIcon,
64
+ class: 'text-yellow-400',
65
+ href: buildUrl(`/docs/${props.type}/${props.domainId}`),
66
+ },
67
+ ];
68
+ ---
69
+
70
+ <VerticalSideBarLayout title={pageTitle} description={ubiquitousLanguage.summary}>
71
+ <main class="flex sm:px-8 docs-layout h-full max-w-7xl">
72
+ <div class="flex docs-layout w-full">
73
+ <div class="w-full lg:mr-2 pr-8 overflow-y-auto py-8 min-h-[50em]">
74
+ <nav class="flex mb-4" aria-label="Breadcrumb">
75
+ <ol class="inline-flex items-center space-x-1 md:space-x-3">
76
+ <li class="inline-flex items-center">
77
+ <a
78
+ href={buildUrl(`/docs/${props.type}/${props.domainId}/language`)}
79
+ class="inline-flex items-center text-sm font-medium text-gray-500 hover:text-primary"
80
+ >
81
+ <svg
82
+ class="w-3 h-3 mr-2.5"
83
+ aria-hidden="true"
84
+ xmlns="http://www.w3.org/2000/svg"
85
+ fill="none"
86
+ viewBox="0 0 24 24"
87
+ stroke-width="2"
88
+ stroke="currentColor"
89
+ >
90
+ <path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"></path>
91
+ </svg>
92
+ Back to ubiquitous language List
93
+ </a>
94
+ </li>
95
+ </ol>
96
+ </nav>
97
+
98
+ <div class="border-b border-gray-200 flex justify-between items-start md:pb-2">
99
+ <div>
100
+ <h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-black">
101
+ {ubiquitousLanguage.name}
102
+ </h2>
103
+ <p class="text-lg pt-2 text-gray-500 font-light">{ubiquitousLanguage.summary}</p>
104
+ <!-- Add bage -->
105
+ {
106
+ badges && (
107
+ <div class="flex flex-wrap py-2 pt-4">
108
+ {badges.map((badge: any) => {
109
+ return (
110
+ <a href={badge.href || '#'} class="pb-2">
111
+ <span
112
+ id={badge.id || ''}
113
+ class={`text-sm font-light text-gray-500 px-2 py-1 rounded-md mr-2 bg-gradient-to-b from-${badge.backgroundColor}-100 to-${badge.backgroundColor}-200 space-x-1 border border-${badge.backgroundColor}-200 text-${badge.textColor}-800 flex items-center ${badge.class ? badge.class : ''} `}
114
+ >
115
+ {badge.icon && <badge.icon className="w-4 h-4 inline-block mr-1 " />}
116
+ {badge.iconURL && <img src={badge.iconURL} class="w-5 h-5 inline-block " />}
117
+ <span>{badge.content}</span>
118
+ </span>
119
+ </a>
120
+ );
121
+ })}
122
+ </div>
123
+ )
124
+ }
125
+ </div>
126
+ </div>
127
+
128
+ {
129
+ ubiquitousLanguage.description && (
130
+ <div class="prose prose-md py-4 max-w-none" set:html={marked.parse(ubiquitousLanguage.description)} />
131
+ )
132
+ }
133
+
134
+ {
135
+ !ubiquitousLanguage.description && (
136
+ <div class="prose prose-md py-4 max-w-none">
137
+ <p>No description for {ubiquitousLanguage.name} available.</p>
138
+ </div>
139
+ )
140
+ }
141
+
142
+ <Footer />
143
+ </div>
144
+ </div>
145
+ <ClientRouter />
146
+ </main>
147
+
148
+ <script>
149
+ function initializeSearch() {
150
+ const searchInput = document.getElementById('searchInput');
151
+ const termCards = document.querySelectorAll('.term-card');
152
+ const noSearchResults = document.getElementById('noSearchResults');
153
+
154
+ searchInput?.addEventListener('input', (e) => {
155
+ const searchTerm = (e.target as HTMLInputElement).value.toLowerCase();
156
+ let visibleCount = 0;
157
+
158
+ termCards.forEach((card) => {
159
+ const title = card.querySelector('h3')?.textContent?.toLowerCase() || '';
160
+ const description = card.querySelector('p')?.textContent?.toLowerCase() || '';
161
+ const matches = title.includes(searchTerm) || description.includes(searchTerm);
162
+
163
+ card.classList.toggle('hidden', !matches);
164
+ if (matches) visibleCount++;
165
+ });
166
+
167
+ // Show/hide no results message
168
+ if (noSearchResults) {
169
+ noSearchResults.classList.toggle('hidden', visibleCount > 0);
170
+ }
171
+ });
172
+ }
173
+
174
+ function initializeShowMore() {
175
+ const cards = document.querySelectorAll('.term-card');
176
+
177
+ cards.forEach((card) => {
178
+ const newCard = card.cloneNode(true);
179
+ if (card.parentNode) {
180
+ card.parentNode.replaceChild(newCard, card);
181
+ // Initially show summary
182
+ const summary = (newCard as Element).querySelector('.summary-text');
183
+ summary?.classList.add('visible');
184
+ }
185
+ newCard.addEventListener('click', () => {
186
+ const description = (newCard as Element).querySelector('.description-text');
187
+ const summary = (newCard as Element).querySelector('.summary-text');
188
+ const showMoreText = (newCard as Element).querySelector('.show-more-text');
189
+
190
+ if (description && summary && showMoreText) {
191
+ (newCard as Element).classList.toggle('expanded');
192
+ description.classList.toggle('visible');
193
+ summary.classList.toggle('visible');
194
+ showMoreText.textContent = description.classList.contains('visible') ? 'Show less' : 'Show more';
195
+ }
196
+ });
197
+ });
198
+ }
199
+
200
+ function highlightMatchingTerm() {
201
+ const urlParams = new URLSearchParams(window.location.search);
202
+ const termId = urlParams.get('id');
203
+
204
+ if (termId) {
205
+ const cards = document.querySelectorAll('.term-card');
206
+ cards.forEach((card) => {
207
+ const termName = card.querySelector('h3')?.textContent?.trim();
208
+ if (termName?.toLowerCase() === termId.toLowerCase()) {
209
+ // Add highlight class
210
+ card.classList.add('highlighted');
211
+ (card as HTMLElement).click();
212
+
213
+ setTimeout(() => {
214
+ // Scroll into view
215
+ card.scrollIntoView({ behavior: 'smooth', block: 'center' });
216
+ }, 300);
217
+ }
218
+ });
219
+ }
220
+ }
221
+
222
+ document.addEventListener('astro:page-load', () => {
223
+ initializeShowMore();
224
+ initializeSearch();
225
+ highlightMatchingTerm();
226
+ });
227
+
228
+ initializeShowMore();
229
+ initializeSearch();
230
+ highlightMatchingTerm();
231
+ </script>
232
+ </VerticalSideBarLayout>
@@ -2,8 +2,9 @@
2
2
  import Footer from '@layouts/Footer.astro';
3
3
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
4
4
  import { getDomains, type Domain, getUbiquitousLanguage } from '@utils/collections/domains';
5
+ import { buildUrl } from '@utils/url-builder';
5
6
  import type { CollectionEntry } from 'astro:content';
6
- import { ViewTransitions } from 'astro:transitions';
7
+ import { ClientRouter } from 'astro:transitions';
7
8
  import * as LucideIcons from 'lucide-react';
8
9
 
9
10
  export async function getStaticPaths() {
@@ -40,7 +41,7 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
40
41
  <ol class="inline-flex items-center space-x-1 md:space-x-3">
41
42
  <li class="inline-flex items-center">
42
43
  <a
43
- href={`/docs/${props.type}/${props.data.id}/${props.data.latestVersion}`}
44
+ href={buildUrl(`/docs/${props.type}/${props.data.id}/${props.data.latestVersion}`)}
44
45
  class="inline-flex items-center text-sm font-medium text-gray-500 hover:text-primary"
45
46
  >
46
47
  <svg
@@ -99,7 +100,7 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
99
100
  ) : (
100
101
  <div id="termsGrid" class="grid grid-cols-1 md:grid-cols-3 gap-4">
101
102
  {ubiquitousLanguage?.data?.dictionary?.map((term) => (
102
- <div class="term-card block bg-white border border-gray-200 rounded-lg p-6 transition-all duration-300 ease-in-out hover:shadow-md hover:border-primary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-primary focus:ring-white min-h-[12em] cursor-pointer">
103
+ <div class="term-card block bg-white border border-gray-200 rounded-lg p-6 transition-all duration-300 ease-in-out hover:shadow-md hover:border-primary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-primary focus:ring-white min-h-[12em]">
103
104
  <div class="flex flex-col h-full space-y-8">
104
105
  {term.icon && (
105
106
  <div>
@@ -119,11 +120,13 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
119
120
  {term.summary}
120
121
  </p>
121
122
  {term.description && (
122
- <div>
123
- <p class="description-text hidden text-gray-600 transition-colors duration-300 ease-in-out group-hover:text-gray-200 m-0 font-light text-sm whitespace-pre-line">
124
- {term.description}
125
- </p>
126
- <span class="show-more-text text-sm text-primary font-medium">Show more</span>
123
+ <div class="prose prose-sm prose-p:my-3">
124
+ <a
125
+ href={buildUrl(`/docs/${props.type}/${props.data.id}/language/${term.id}`)}
126
+ class="show-more-text text-sm text-primary font-medium hover:underline"
127
+ >
128
+ Read more
129
+ </a>
127
130
  </div>
128
131
  )}
129
132
  </div>
@@ -146,7 +149,7 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
146
149
  <Footer />
147
150
  </div>
148
151
  </div>
149
- <ViewTransitions />
152
+ <ClientRouter />
150
153
  </main>
151
154
 
152
155
  <script>
@@ -177,27 +180,11 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
177
180
 
178
181
  function initializeShowMore() {
179
182
  const cards = document.querySelectorAll('.term-card');
180
-
181
183
  cards.forEach((card) => {
182
- const newCard = card.cloneNode(true);
183
- if (card.parentNode) {
184
- card.parentNode.replaceChild(newCard, card);
185
- // Initially show summary
186
- const summary = (newCard as Element).querySelector('.summary-text');
187
- summary?.classList.add('visible');
184
+ const summary = card.querySelector('.summary-text');
185
+ if (summary) {
186
+ summary.classList.add('visible');
188
187
  }
189
- newCard.addEventListener('click', () => {
190
- const description = (newCard as Element).querySelector('.description-text');
191
- const summary = (newCard as Element).querySelector('.summary-text');
192
- const showMoreText = (newCard as Element).querySelector('.show-more-text');
193
-
194
- if (description && summary && showMoreText) {
195
- (newCard as Element).classList.toggle('expanded');
196
- description.classList.toggle('visible');
197
- summary.classList.toggle('visible');
198
- showMoreText.textContent = description.classList.contains('visible') ? 'Show less' : 'Show more';
199
- }
200
- });
201
188
  });
202
189
  }
203
190
 
@@ -240,42 +227,14 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
240
227
  min-height: 12em;
241
228
  }
242
229
 
243
- .term-card.expanded {
244
- min-height: 24em;
245
- background-color: rgb(249 250 251);
246
- z-index: 10;
247
- box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
248
- }
249
-
250
- .summary-text,
251
- .description-text {
252
- transition:
253
- opacity 0.3s ease-in-out,
254
- max-height 0.3s ease-in-out;
255
- opacity: 0;
256
- max-height: 0;
257
- overflow: hidden;
258
- display: none;
259
- }
260
-
261
- .summary-text.visible,
262
- .description-text.visible {
230
+ .summary-text {
263
231
  opacity: 1;
264
- max-height: 500px;
265
- margin-bottom: 1rem;
266
- display: block;
267
- }
268
-
269
- .description-text {
270
- white-space: pre-line;
271
- line-height: 1.5;
272
- }
273
-
274
- .show-more-text {
232
+ max-height: unset;
275
233
  display: block;
276
- margin-top: 0.5rem;
277
234
  }
278
235
 
236
+ .description-text,
237
+ .term-card.expanded,
279
238
  .term-card.expanded .show-more-text {
280
239
  display: none;
281
240
  }
@@ -6,7 +6,7 @@ import { getFlows } from '@utils/collections/flows';
6
6
  import { buildUrl } from '@utils/url-builder';
7
7
 
8
8
  import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
9
- import { ViewTransitions } from 'astro:transitions';
9
+ import { ClientRouter } from 'astro:transitions';
10
10
  type PageTypesWithFlows = PageTypes | 'flows';
11
11
 
12
12
  export async function getStaticPaths() {
@@ -58,7 +58,7 @@ const {
58
58
  }}
59
59
  />
60
60
  </div>
61
- <ViewTransitions />
61
+ <ClientRouter />
62
62
  </VisualiserLayout>
63
63
 
64
64
  <script define:vars={{ id }}>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
3
- import { ViewTransitions } from 'astro:transitions';
3
+ import { ClientRouter } from 'astro:transitions';
4
4
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
5
5
  ---
6
6
 
@@ -26,5 +26,5 @@ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
26
26
  }}
27
27
  />
28
28
  </div>
29
- <ViewTransitions />
29
+ <ClientRouter />
30
30
  </VerticalSideBarLayout>
@@ -8,7 +8,7 @@ export const getChangeLogs = async (item: CollectionEntry<CollectionTypes>): Pro
8
8
 
9
9
  // Get all logs for collection type and filter by given collection
10
10
  const logs = await getCollection('changelogs', (log) => {
11
- return log.id.includes(`${collection}/`) && log.id.includes(slug);
11
+ return log.id.includes(`${collection}/`) && log.slug.includes(slug);
12
12
  });
13
13
 
14
14
  const hydratedLogs = logs.map((log) => {
@@ -0,0 +1,43 @@
1
+ import { getCollection, type CollectionEntry } from 'astro:content';
2
+
3
+ const getOwners = (function () {
4
+ type Owners = CollectionEntry<'users' | 'teams'>;
5
+ let cachedOwners: Map<string, Owners> | null = null;
6
+ let initializingPromise: Promise<Map<string, Owners>> | null = null;
7
+
8
+ /**
9
+ * Initializes and caches the owners by fetching from the 'users' and 'teams' collections.
10
+ */
11
+ async function init() {
12
+ const ownersMap = new Map<string, CollectionEntry<'users' | 'teams'>>();
13
+
14
+ const owners = await Promise.all([
15
+ getCollection('users', (entry) => entry.data.hidden !== true),
16
+ getCollection('teams', (entry) => entry.data.hidden !== true),
17
+ ]);
18
+
19
+ for (const owner of owners.flat()) {
20
+ ownersMap.set(owner.data.id, owner);
21
+ }
22
+
23
+ cachedOwners = ownersMap;
24
+ initializingPromise = null;
25
+
26
+ return cachedOwners;
27
+ }
28
+
29
+ return () =>
30
+ cachedOwners || // Return cached owners if already initialized
31
+ initializingPromise || // Return the promise if initialization is in progress
32
+ (initializingPromise = init()); // Initialize if neither cache nor promise exists
33
+ })();
34
+
35
+ export async function getOwner(lookup: { id: string }): Promise<CollectionEntry<'users' | 'teams'> | undefined> {
36
+ const lookupId = typeof lookup === 'string' ? lookup : lookup.id;
37
+
38
+ const owner = (await getOwners()).get(lookupId);
39
+
40
+ if (!owner) console.warn(`Entry ${lookupId} not found in "teams"/"users" collections.`);
41
+
42
+ return owner;
43
+ }