@eventcatalog/core 3.39.5 → 3.39.6

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 (69) 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-M4S7PORQ.js → chunk-4OSFLWLG.js} +1 -1
  6. package/dist/{chunk-TNE5QSJ4.js → chunk-IKZ5ITXP.js} +1 -1
  7. package/dist/{chunk-S4HLJWQ7.js → chunk-LEUIMTEQ.js} +1 -1
  8. package/dist/{chunk-KVAEAYEP.js → chunk-MQAZ4LXP.js} +1 -1
  9. package/dist/{chunk-H5BZMNK3.js → chunk-ORVOST63.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/docs/api/03-domain-api.md +16 -0
  13. package/dist/docs/api/04-service-api.md +16 -0
  14. package/dist/docs/api/05-command-api.md +16 -0
  15. package/dist/docs/api/06-event-api.md +16 -0
  16. package/dist/docs/api/06-query-api.md +16 -0
  17. package/dist/docs/api/08-channel-api.md +16 -0
  18. package/dist/docs/api/09-flow-api.md +16 -0
  19. package/dist/docs/api/10-entity-api.md +15 -0
  20. package/dist/docs/api/12-data-product-api.md +17 -0
  21. package/dist/docs/development/01-fundamentals.md +7 -0
  22. package/dist/docs/development/01-getting-started/installation.md +8 -0
  23. package/dist/docs/development/01-getting-started/project-structure.md +2 -0
  24. package/dist/docs/development/bring-your-own-documentation/01-introduction.md +3 -1
  25. package/dist/docs/development/customization/customize-sidebars/00-application-sidebar.md +45 -5
  26. package/dist/docs/editor/00-overview.md +73 -0
  27. package/dist/docs/editor/01-first-edit.md +124 -0
  28. package/dist/docs/editor/_category_.json +12 -0
  29. package/dist/docs/editor/explanation/_category_.json +11 -0
  30. package/dist/docs/editor/explanation/beta-status-feedback.md +48 -0
  31. package/dist/docs/editor/explanation/how-it-works.md +49 -0
  32. package/dist/docs/editor/explanation/markdown-mdx-git.md +58 -0
  33. package/dist/docs/editor/how-to/_category_.json +11 -0
  34. package/dist/docs/editor/how-to/add-schemas-and-specifications.md +66 -0
  35. package/dist/docs/editor/how-to/edit-resource.md +88 -0
  36. package/dist/docs/editor/how-to/invite-editors.md +68 -0
  37. package/dist/docs/editor/how-to/open-catalog.md +44 -0
  38. package/dist/docs/editor/how-to/preview-changes.md +55 -0
  39. package/dist/docs/editor/how-to/revert-local-changes.md +43 -0
  40. package/dist/docs/editor/how-to/review-and-commit-changes.md +57 -0
  41. package/dist/docs/editor/how-to/run-locally.md +71 -0
  42. package/dist/docs/editor/how-to/use-flow-editor.md +66 -0
  43. package/dist/docs/editor/how-to/use-slash-commands.md +67 -0
  44. package/dist/docs/editor/reference/_category_.json +11 -0
  45. package/dist/docs/editor/reference/cli.md +61 -0
  46. package/dist/docs/editor/reference/supported-content.md +81 -0
  47. package/dist/docs/editor/reference/supported-resources.md +51 -0
  48. package/dist/docs/editor/reference/troubleshooting.md +76 -0
  49. package/dist/eventcatalog.cjs +1 -1
  50. package/dist/eventcatalog.js +5 -5
  51. package/dist/generate.cjs +1 -1
  52. package/dist/generate.js +3 -3
  53. package/dist/utils/cli-logger.cjs +1 -1
  54. package/dist/utils/cli-logger.js +2 -2
  55. package/eventcatalog/src/components/Badge.astro +50 -0
  56. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +1 -0
  57. package/eventcatalog/src/components/Tables/Discover/columns.tsx +35 -13
  58. package/eventcatalog/src/components/Tables/Table.tsx +1 -0
  59. package/eventcatalog/src/components/Tables/columns/SharedColumns.tsx +24 -11
  60. package/eventcatalog/src/content.config-shared-collections.ts +1 -0
  61. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +2 -18
  62. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +2 -14
  63. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +2 -14
  64. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +3 -15
  65. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +2 -18
  66. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +2 -18
  67. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +2 -11
  68. package/eventcatalog/src/utils/badge-styles.ts +31 -0
  69. package/package.json +4 -4
@@ -1,11 +1,17 @@
1
1
  import { createColumnHelper } from '@tanstack/react-table';
2
2
  import { useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { DocumentTextIcon, MapIcon } from '@heroicons/react/24/solid';
4
- import { ArrowDownIcon, ArrowUpIcon, EllipsisVerticalIcon, StarIcon } from '@heroicons/react/24/outline';
4
+ import {
5
+ ArrowDownIcon,
6
+ ArrowTopRightOnSquareIcon,
7
+ ArrowUpIcon,
8
+ EllipsisVerticalIcon,
9
+ StarIcon,
10
+ } from '@heroicons/react/24/outline';
5
11
  import { buildUrl } from '@utils/url-builder';
6
12
  import { getColorAndIconForCollection } from '@utils/collections/icons';
7
13
  import { getCollectionTextColorClass } from '@utils/collection-colors';
8
- import { getBadgeReactStyle } from '@utils/badge-styles';
14
+ import { getBadgeHref, getBadgeReactStyle } from '@utils/badge-styles';
9
15
  import { isIconPath, resolveIconUrl } from '@utils/icon';
10
16
  import { useStore } from '@nanostores/react';
11
17
  import { favoritesStore, toggleFavorite, type FavoriteItem } from '../../../stores/favorites-store';
@@ -15,7 +21,11 @@ import type { TableConfiguration } from '@types';
15
21
  const columnHelper = createColumnHelper<DiscoverTableData>();
16
22
 
17
23
  // Badge cell component (proper React component to use hooks)
18
- const BadgesCell = ({ badges }: { badges: Array<{ content: string; backgroundColor?: string; textColor?: string }> }) => {
24
+ const BadgesCell = ({
25
+ badges,
26
+ }: {
27
+ badges: Array<{ content: string; backgroundColor?: string; textColor?: string; url?: string }>;
28
+ }) => {
19
29
  const [isExpanded, setIsExpanded] = useState(false);
20
30
 
21
31
  if (!badges || badges.length === 0) return <span className="text-xs text-[rgb(var(--ec-icon-color))]">-</span>;
@@ -25,16 +35,28 @@ const BadgesCell = ({ badges }: { badges: Array<{ content: string; backgroundCol
25
35
 
26
36
  return (
27
37
  <div className="flex flex-col gap-1 items-start">
28
- {visibleItems.map((badge, index) => (
29
- <span
30
- key={`${badge.content}-${index}`}
31
- className="inline-flex items-center px-2 py-0.5 text-[11px] font-normal rounded-md max-w-[140px] truncate border border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text-muted))] bg-transparent"
32
- style={getBadgeReactStyle(badge)}
33
- title={badge.content}
34
- >
35
- {badge.content}
36
- </span>
37
- ))}
38
+ {visibleItems.map((badge, index) => {
39
+ const href = getBadgeHref(badge);
40
+ const className =
41
+ 'inline-flex items-center px-2 py-0.5 text-[11px] font-normal rounded-md max-w-[140px] truncate border border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text-muted))] bg-transparent';
42
+
43
+ return href ? (
44
+ <a
45
+ key={`${badge.content}-${index}`}
46
+ href={href}
47
+ className={className}
48
+ style={getBadgeReactStyle(badge)}
49
+ title={badge.content}
50
+ >
51
+ <span className="truncate">{badge.content}</span>
52
+ <ArrowTopRightOnSquareIcon className="ml-1 h-3 w-3 shrink-0 opacity-70" aria-hidden="true" />
53
+ </a>
54
+ ) : (
55
+ <span key={`${badge.content}-${index}`} className={className} style={getBadgeReactStyle(badge)} title={badge.content}>
56
+ {badge.content}
57
+ </span>
58
+ );
59
+ })}
38
60
  {hiddenCount > 0 && (
39
61
  <button onClick={() => setIsExpanded(!isExpanded)} className="text-xs text-[rgb(var(--ec-accent))] hover:underline">
40
62
  {isExpanded ? 'less' : `+${hiddenCount}`}
@@ -58,6 +58,7 @@ export type TData<T extends TCollectionTypes> = {
58
58
  backgroundColor: string;
59
59
  textColor: string;
60
60
  icon: any; // Where is it defined?
61
+ url?: string;
61
62
  }>;
62
63
  // ---------------------------------------------------------------------------
63
64
  // Domains
@@ -1,6 +1,7 @@
1
1
  import { createColumnHelper } from '@tanstack/react-table';
2
2
  import { useState } from 'react';
3
- import { getBadgeReactStyle } from '@utils/badge-styles';
3
+ import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid';
4
+ import { getBadgeHref, getBadgeReactStyle } from '@utils/badge-styles';
4
5
  import { filterByBadge } from '../filters/custom-filters';
5
6
  import type { TCollectionTypes, TData } from '../Table';
6
7
  import type { TableConfiguration } from '@types';
@@ -24,16 +25,28 @@ export const createBadgesColumn = <T extends { data: Pick<TData<U>['data'], 'bad
24
25
 
25
26
  return (
26
27
  <div className="flex flex-wrap gap-1 items-center">
27
- {visibleItems.map((badge, index) => (
28
- <span
29
- key={`${badge.id}-${index}`}
30
- className="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-md border border-[rgb(var(--ec-accent)/0.5)] text-[rgb(var(--ec-page-text))] bg-transparent"
31
- style={getBadgeReactStyle(badge)}
32
- title={badge.content}
33
- >
34
- {badge.content}
35
- </span>
36
- ))}
28
+ {visibleItems.map((badge, index) => {
29
+ const href = getBadgeHref(badge);
30
+ const className =
31
+ 'inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-md border border-[rgb(var(--ec-accent)/0.5)] text-[rgb(var(--ec-page-text))] bg-transparent';
32
+
33
+ return href ? (
34
+ <a
35
+ key={`${badge.id}-${index}`}
36
+ href={href}
37
+ className={className}
38
+ style={getBadgeReactStyle(badge)}
39
+ title={badge.content}
40
+ >
41
+ <span>{badge.content}</span>
42
+ <ArrowTopRightOnSquareIcon className="ml-1 h-3 w-3 shrink-0 opacity-70" aria-hidden="true" />
43
+ </a>
44
+ ) : (
45
+ <span key={`${badge.id}-${index}`} className={className} style={getBadgeReactStyle(badge)} title={badge.content}>
46
+ {badge.content}
47
+ </span>
48
+ );
49
+ })}
37
50
  {hiddenCount > 0 && (
38
51
  <button onClick={() => setIsExpanded(!isExpanded)} className="text-xs text-[rgb(var(--ec-accent))] hover:underline">
39
52
  {isExpanded ? 'less' : `+${hiddenCount}`}
@@ -6,6 +6,7 @@ export const badge = z.object({
6
6
  backgroundColor: z.string(),
7
7
  textColor: z.string(),
8
8
  icon: z.string().optional(),
9
+ url: z.string().optional(),
9
10
  });
10
11
 
11
12
  // Create a union type for owners
@@ -5,6 +5,7 @@ import config from '@config';
5
5
  import { AlignLeftIcon, UserIcon, UsersIcon } from 'lucide-react';
6
6
 
7
7
  import mdxComponents from '@components/MDX/components';
8
+ import Badge from '@components/Badge.astro';
8
9
 
9
10
  import { getOwner } from '@utils/collections/owners';
10
11
  import { buildUrl, buildEditUrlForResource } from '@utils/url-builder';
@@ -117,24 +118,7 @@ const editUrl =
117
118
  badges && badges.length > 0 && (
118
119
  <div class="flex flex-wrap gap-3 py-2">
119
120
  {badges.map((badge: any) => {
120
- return (
121
- <a href={badge.url || '#'}>
122
- <span
123
- id={badge.id || ''}
124
- class={`
125
- inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
126
- bg-[rgb(var(--ec-content-hover))] border border-[rgb(var(--ec-page-border))]
127
- text-[rgb(var(--ec-page-text))]
128
- shadow-xs
129
- ${badge.class ? badge.class : ''}
130
- `}
131
- >
132
- {badge.icon && <badge.icon className="w-4 h-4 flex-shrink-0 text-[rgb(var(--ec-icon-color))]" />}
133
- {badge.iconURL && <img src={badge.iconURL} class="w-4 h-4 flex-shrink-0 opacity-80" alt="" />}
134
- <span>{badge.content}</span>
135
- </span>
136
- </a>
137
- );
121
+ return <Badge badge={badge} />;
138
122
  })}
139
123
  </div>
140
124
  )
@@ -5,11 +5,11 @@ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
5
5
  import Admonition from '@components/MDX/Admonition';
6
6
  import components from '@components/MDX/components';
7
7
  import CopyAsMarkdown from '@components/CopyAsMarkdown';
8
+ import Badge from '@components/Badge.astro';
8
9
  import { buildUrl } from '@utils/url-builder';
9
10
  import { AlignLeftIcon, HistoryIcon } from 'lucide-react';
10
11
  import { isEventCatalogChatEnabled, isResourceDocsEnabled } from '@utils/feature';
11
12
  import { getIcon } from '@utils/badges';
12
- import { getBadgeStyle } from '@utils/badge-styles';
13
13
  import { collectionToResourceMap } from '@utils/collections/util';
14
14
 
15
15
  import { Page } from './_index.data';
@@ -80,19 +80,7 @@ const pagefindAttributes =
80
80
  {
81
81
  badges.length > 0 && (
82
82
  <div class="flex flex-wrap gap-3 py-4">
83
- {badges.map((badge: any) => (
84
- <span
85
- class={`
86
- inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
87
- ${badge.backgroundColor ? 'bg-[rgb(var(--ec-content-hover))]' : 'bg-transparent'} border border-[rgb(var(--ec-page-border))]
88
- text-[rgb(var(--ec-page-text))]
89
- `}
90
- style={getBadgeStyle(badge)}
91
- >
92
- {badge.iconComponent && <badge.iconComponent className="w-4 h-4 flex-shrink-0" />}
93
- <span>{badge.content}</span>
94
- </span>
95
- ))}
83
+ {badges.map((badge: any) => <Badge badge={badge} />)}
96
84
  </div>
97
85
  )
98
86
  }
@@ -5,11 +5,11 @@ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
5
5
  import Admonition from '@components/MDX/Admonition';
6
6
  import components from '@components/MDX/components';
7
7
  import CopyAsMarkdown from '@components/CopyAsMarkdown';
8
+ import Badge from '@components/Badge.astro';
8
9
  import { buildUrl } from '@utils/url-builder';
9
10
  import { AlignLeftIcon, HistoryIcon } from 'lucide-react';
10
11
  import { isEventCatalogChatEnabled, isResourceDocsEnabled } from '@utils/feature';
11
12
  import { getIcon } from '@utils/badges';
12
- import { getBadgeStyle } from '@utils/badge-styles';
13
13
  import { collectionToResourceMap } from '@utils/collections/util';
14
14
 
15
15
  import { Page } from './_index.data';
@@ -73,19 +73,7 @@ const pagefindAttributes =
73
73
  {
74
74
  badges.length > 0 && (
75
75
  <div class="flex flex-wrap gap-3 py-4">
76
- {badges.map((badge: any) => (
77
- <span
78
- class={`
79
- inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
80
- ${badge.backgroundColor ? 'bg-[rgb(var(--ec-content-hover))]' : 'bg-transparent'} border border-[rgb(var(--ec-page-border))]
81
- text-[rgb(var(--ec-page-text))]
82
- `}
83
- style={getBadgeStyle(badge)}
84
- >
85
- {badge.iconComponent && <badge.iconComponent className="w-4 h-4 flex-shrink-0" />}
86
- <span>{badge.content}</span>
87
- </span>
88
- ))}
76
+ {badges.map((badge: any) => <Badge badge={badge} />)}
89
77
  </div>
90
78
  )
91
79
  }
@@ -15,10 +15,10 @@ import mdxComponents from '@components/MDX/components';
15
15
  import 'diff2html/bundles/css/diff2html.min.css';
16
16
 
17
17
  import { buildUrl } from '@utils/url-builder';
18
- import { getBadgeStyle } from '@utils/badge-styles';
19
18
  import { getPreviousVersion } from '@utils/collections/util';
20
19
  import { getDiffsForCurrentAndPreviousVersion } from '@utils/file-diffs';
21
20
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
21
+ import Badge from '@components/Badge.astro';
22
22
  import { ClientRouter } from 'astro:transitions';
23
23
  import { isChangelogEnabled } from '@utils/feature';
24
24
 
@@ -143,13 +143,7 @@ const badges = [getBadge()];
143
143
  badges && (
144
144
  <div class="flex flex-wrap py-2 pt-4">
145
145
  {badges.map((badge: any) => (
146
- <span
147
- class="text-sm font-medium px-2 py-1 rounded-md mr-2 space-x-1 flex items-center bg-transparent border border-[rgb(var(--ec-page-border))]"
148
- style={getBadgeStyle(badge)}
149
- >
150
- {badge.icon && <badge.icon className="w-4 h-4 inline-block mr-1" />}
151
- <span>{badge.content}</span>
152
- </span>
146
+ <Badge badge={badge} className="mr-2 px-2 py-1 rounded-md" />
153
147
  ))}
154
148
  </div>
155
149
  )
@@ -195,13 +189,7 @@ const badges = [getBadge()];
195
189
  {log.badges && (
196
190
  <div class="flex flex-wrap">
197
191
  {log.badges.map((badge: any) => (
198
- <span
199
- class="text-sm font-medium px-2 py-1 rounded-md mr-2 space-x-1 flex items-center bg-[rgb(var(--ec-badge-default-bg))] text-[rgb(var(--ec-badge-default-text))]"
200
- style={getBadgeStyle(badge)}
201
- >
202
- {badge.icon && <badge.icon className="w-4 h-4 inline-block mr-1" />}
203
- <span>{badge.content}</span>
204
- </span>
192
+ <Badge badge={badge} className="mr-2 px-2 py-1 rounded-md" />
205
193
  ))}
206
194
  </div>
207
195
  )}
@@ -7,8 +7,8 @@ import Footer from '@layouts/Footer.astro';
7
7
  import { Page } from './_[filename].data';
8
8
  import { getAbsoluteFilePathForAstroFile } from '@utils/files';
9
9
  import { buildUrl, buildEditUrlForResource } from '@utils/url-builder';
10
- import { getBadgeStyle } from '@utils/badge-styles';
11
10
  import Admonition from '@components/MDX/Admonition';
11
+ import Badge from '@components/Badge.astro';
12
12
 
13
13
  import { ServerIcon } from '@heroicons/react/24/outline';
14
14
 
@@ -83,23 +83,7 @@ const pagefindAttributes =
83
83
  badges && badges.length > 0 && (
84
84
  <div class="flex flex-wrap gap-3 py-4">
85
85
  {badges.map((badge: any) => {
86
- return (
87
- <span
88
- id={badge.id || ''}
89
- class={`
90
- inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
91
- ${badge.backgroundColor ? 'bg-[rgb(var(--ec-content-hover))]' : 'bg-transparent'} border border-[rgb(var(--ec-page-border))]
92
- text-[rgb(var(--ec-page-text))]
93
- shadow-xs
94
- ${badge.class ? badge.class : ''}
95
- `}
96
- style={getBadgeStyle(badge)}
97
- >
98
- {badge.icon && <badge.icon className="w-4 h-4 flex-shrink-0" />}
99
- {badge.iconURL && <img src={badge.iconURL} class="w-4 h-4 flex-shrink-0 opacity-80" alt="" />}
100
- <span>{badge.content}</span>
101
- </span>
102
- );
86
+ return <Badge badge={badge} />;
103
87
  })}
104
88
  </div>
105
89
  )
@@ -15,6 +15,7 @@ import Admonition from '@components/MDX/Admonition';
15
15
  import VersionList from '@components/Lists/VersionList.astro';
16
16
  import CopyAsMarkdown from '@components/CopyAsMarkdown';
17
17
  import FavoriteButton from '@components/FavoriteButton';
18
+ import Badge from '@components/Badge.astro';
18
19
  import { shouldRenderSideBarSection } from '@stores/sidebar-store/builders/shared';
19
20
 
20
21
  import {
@@ -34,7 +35,6 @@ import { getSpecificationsForService } from '@utils/collections/services';
34
35
  import { resourceToCollectionMap, collectionToResourceMap, getDeprecatedDetails } from '@utils/collections/util';
35
36
  import { getSchemasFromResource } from '@utils/collections/schemas';
36
37
  import { getIcon } from '@utils/badges';
37
- import { getBadgeStyle } from '@utils/badge-styles';
38
38
  import { buildUrl, buildEditUrlForResource } from '@utils/url-builder';
39
39
  import { isIconPath, resolveIconUrl } from '@utils/icon';
40
40
  import {
@@ -377,23 +377,7 @@ if (!hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
377
377
  badges && (
378
378
  <div class="flex flex-wrap gap-3 pt-6 pb-2">
379
379
  {badges.map((badge: any) => {
380
- return (
381
- <span
382
- id={badge.id || ''}
383
- class={`
384
- inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
385
- ${badge.backgroundColor ? 'bg-[rgb(var(--ec-content-hover))]' : 'bg-transparent'} border border-[rgb(var(--ec-page-border))]
386
- text-[rgb(var(--ec-page-text))]
387
- shadow-xs
388
- ${badge.class ? badge.class : ''}
389
- `}
390
- style={getBadgeStyle(badge)}
391
- >
392
- {badge.icon && <badge.icon className="w-4 h-4 flex-shrink-0" />}
393
- {badge.iconURL && <img src={badge.iconURL} class="w-4 h-4 flex-shrink-0 opacity-80" alt="" />}
394
- <span>{badge.content}</span>
395
- </span>
396
- );
380
+ return <Badge badge={badge} />;
397
381
  })}
398
382
  </div>
399
383
  )
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import RectangleGroupIcon from '@heroicons/react/24/outline/RectangleGroupIcon';
3
+ import Badge from '@components/Badge.astro';
3
4
  import Footer from '@layouts/Footer.astro';
4
5
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
5
6
  import { buildUrl } from '@utils/url-builder';
@@ -80,17 +81,7 @@ const badges = [
80
81
  badges && badges.length > 0 && (
81
82
  <div class="flex flex-wrap gap-3 py-4">
82
83
  {badges.map((badge: any) => {
83
- return (
84
- <span
85
- class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
86
- bg-[rgb(var(--ec-content-hover))] border border-[rgb(var(--ec-page-border))]
87
- text-[rgb(var(--ec-page-text))] shadow-xs"
88
- >
89
- {badge.icon && <badge.icon className="w-4 h-4 flex-shrink-0 text-[rgb(var(--ec-icon-color))]" />}
90
- {badge.iconURL && <img src={badge.iconURL} class="w-4 h-4 flex-shrink-0 opacity-80" alt="" />}
91
- <span>{badge.content}</span>
92
- </span>
93
- );
84
+ return <Badge badge={badge} />;
94
85
  })}
95
86
  </div>
96
87
  )
@@ -1,8 +1,23 @@
1
+ import { buildUrl } from './url-builder';
2
+
1
3
  type BadgeColorKind = 'background' | 'text';
2
4
 
3
5
  type Badge = {
4
6
  backgroundColor?: string;
5
7
  textColor?: string;
8
+ url?: string;
9
+ };
10
+
11
+ const URL_SCHEME_PATTERN = /^[a-z][a-z\d+\-.]*:/i;
12
+ const PROTOCOL_RELATIVE_URL_PATTERN = /^\/\//;
13
+ const SAFE_BADGE_URL_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);
14
+
15
+ const isAlreadyBasePrefixed = (url: string) => {
16
+ const baseUrl = import.meta.env.BASE_URL;
17
+ if (!baseUrl || baseUrl === '/') return false;
18
+
19
+ const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
20
+ return url === normalizedBaseUrl || url.startsWith(`${normalizedBaseUrl}/`);
6
21
  };
7
22
 
8
23
  const NAMED_BADGE_COLOR_KEYS = new Set([
@@ -204,3 +219,19 @@ export const getBadgeReactStyle = (badge: Badge) => {
204
219
  ...(color ? { color } : {}),
205
220
  };
206
221
  };
222
+
223
+ export const getBadgeHref = (badge: Badge) => {
224
+ if (!badge.url) return undefined;
225
+
226
+ const url = badge.url.trim();
227
+ if (!url) return undefined;
228
+ if (url.startsWith('#') || url.startsWith('?') || PROTOCOL_RELATIVE_URL_PATTERN.test(url)) return url;
229
+
230
+ const scheme = URL_SCHEME_PATTERN.exec(url)?.[0].toLowerCase();
231
+ if (scheme) return SAFE_BADGE_URL_SCHEMES.has(scheme) ? url : undefined;
232
+
233
+ if (isAlreadyBasePrefixed(url)) return url;
234
+ if (url.startsWith('/')) return buildUrl(url);
235
+
236
+ return url;
237
+ };
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "license": "SEE LICENSE IN LICENSE",
9
9
  "type": "module",
10
- "version": "3.39.5",
10
+ "version": "3.39.6",
11
11
  "publishConfig": {
12
12
  "access": "public"
13
13
  },
@@ -106,9 +106,9 @@
106
106
  "update-notifier": "^7.3.1",
107
107
  "uuid": "^10.0.0",
108
108
  "zod": "^4.3.6",
109
- "@eventcatalog/linter": "1.0.23",
110
- "@eventcatalog/visualiser": "^3.21.0",
111
- "@eventcatalog/sdk": "2.21.1"
109
+ "@eventcatalog/sdk": "2.21.2",
110
+ "@eventcatalog/linter": "1.0.24",
111
+ "@eventcatalog/visualiser": "^3.21.0"
112
112
  },
113
113
  "devDependencies": {
114
114
  "@astrojs/check": "^0.9.9",