@eventcatalog/core 3.30.0 → 3.31.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 (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-6UG4JMUV.js → chunk-7IGMIOQF.js} +1 -1
  6. package/dist/{chunk-Z26P4PCB.js → chunk-HVOLSUC2.js} +1 -1
  7. package/dist/{chunk-RRBDF4MM.js → chunk-LWVHWR77.js} +1 -1
  8. package/dist/{chunk-MVZKHUX2.js → chunk-QIJOBQZ7.js} +1 -1
  9. package/dist/{chunk-ATRBVTJ6.js → chunk-UY5QDWK7.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/astro.config.mjs +10 -6
  19. package/eventcatalog/public/logo.png +0 -0
  20. package/eventcatalog/src/components/CopyAsMarkdown.tsx +29 -24
  21. package/eventcatalog/src/components/MDX/Design/Design.astro +1 -1
  22. package/eventcatalog/src/components/MDX/Tiles/Tile.astro +11 -8
  23. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +218 -0
  24. package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +265 -0
  25. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +371 -0
  26. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +183 -0
  27. package/eventcatalog/src/components/Settings/LogoUpload.tsx +137 -0
  28. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +91 -0
  29. package/eventcatalog/src/components/Settings/ReadOnlyBanner.tsx +18 -0
  30. package/eventcatalog/src/components/Settings/Row.tsx +59 -0
  31. package/eventcatalog/src/components/Settings/SettingsShared.tsx +176 -0
  32. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +17 -18
  33. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +45 -16
  34. package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +2 -2
  35. package/eventcatalog/src/content.config.ts +1 -1
  36. package/eventcatalog/src/enterprise/auth/middleware/middleware-auth.ts +11 -7
  37. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +4 -4
  38. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +70 -57
  39. package/eventcatalog/src/enterprise/feature.ts +2 -1
  40. package/eventcatalog/src/layouts/SettingsLayout.astro +116 -0
  41. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +62 -23
  42. package/eventcatalog/src/pages/_index.astro +250 -255
  43. package/eventcatalog/src/pages/api/settings/ai.ts +57 -0
  44. package/eventcatalog/src/pages/api/settings/general.ts +71 -0
  45. package/eventcatalog/src/pages/api/settings/logo.ts +113 -0
  46. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -1
  47. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +26 -32
  48. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
  49. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +40 -31
  50. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -1
  51. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +2 -26
  52. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +5 -1
  53. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -1
  54. package/eventcatalog/src/pages/settings/assistant.astro +37 -0
  55. package/eventcatalog/src/pages/settings/billing.astro +17 -0
  56. package/eventcatalog/src/pages/settings/general.astro +32 -0
  57. package/eventcatalog/src/pages/settings/index.astro +21 -0
  58. package/eventcatalog/src/pages/settings/llm-access.astro +34 -0
  59. package/eventcatalog/src/pages/settings/mcp.astro +14 -0
  60. package/eventcatalog/src/styles/theme.css +38 -29
  61. package/eventcatalog/src/styles/themes/forest.css +17 -9
  62. package/eventcatalog/src/styles/themes/ocean.css +10 -2
  63. package/eventcatalog/src/styles/themes/sapphire.css +10 -2
  64. package/eventcatalog/src/styles/themes/sunset.css +25 -17
  65. package/eventcatalog/src/utils/eventcatalog-config/config-schema.ts +49 -0
  66. package/eventcatalog/src/utils/eventcatalog-config/config-writer.ts +149 -0
  67. package/eventcatalog/src/utils/url-builder.ts +4 -2
  68. package/package.json +7 -5
  69. package/eventcatalog/src/pages/docs/llm/llms-services.txt.ts +0 -81
@@ -1,16 +1,14 @@
1
1
  ---
2
2
  import { buildUrl } from '@utils/url-builder';
3
- import { ArrowRightIcon, PlusIcon } from '@heroicons/react/24/outline';
4
3
  import config from '@config';
5
4
 
6
5
  import { getCollection } from 'astro:content';
7
6
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
8
- import { BookOpenText, Workflow, TableProperties, BookUser, Code2, FileJson } from 'lucide-react';
7
+ import { BookOpenText, Workflow, TableProperties, BookUser, Code2, FileJson, ArrowUpRight, ArrowRight, Plus } from 'lucide-react';
9
8
 
10
9
  const { showNestedSideBar = true } = Astro.props;
11
10
 
12
11
  // Lightweight data fetch: only raw collections, no hydration.
13
- // The homepage only needs counts + one item per type for default URLs.
14
12
  const [allDomains, allServices, allEvents, allCommands, allQueries, allFlows] = await Promise.all([
15
13
  getCollection('domains'),
16
14
  getCollection('services'),
@@ -25,11 +23,13 @@ const isCurrentVersion = (item: { data: { hidden?: boolean }; filePath?: string
25
23
 
26
24
  const domains = allDomains.filter(isCurrentVersion);
27
25
  const services = allServices.filter(isCurrentVersion);
28
- const messages = [...allEvents, ...allCommands, ...allQueries].filter(isCurrentVersion);
26
+ const events = allEvents.filter(isCurrentVersion);
27
+ const commands = allCommands.filter(isCurrentVersion);
28
+ const queries = allQueries.filter(isCurrentVersion);
29
+ const messages = [...events, ...commands, ...queries];
29
30
  const flows = allFlows.filter(isCurrentVersion);
30
31
 
31
- // Check if catalog has content
32
- const hasContent = domains.length > 0 || services.length > 0 || messages.length > 0 || flows.length > 0;
32
+ const totalResources = domains.length + services.length + messages.length + flows.length;
33
33
 
34
34
  const getDefaultUrl = (route: string, defaultValue: string) => {
35
35
  if (domains.length > 0) return buildUrl(`/${route}/domains/${domains[0].data.id}/${domains[0].data.version}`);
@@ -38,328 +38,323 @@ const getDefaultUrl = (route: string, defaultValue: string) => {
38
38
  return buildUrl(defaultValue);
39
39
  };
40
40
 
41
- const topTiles = [
41
+ interface StatTile {
42
+ label: string;
43
+ count: number;
44
+ href: string;
45
+ emptyHref: string;
46
+ tone: string; // CSS color expression — drives accent rail + count gradient
47
+ }
48
+
49
+ const statTiles: StatTile[] = [
42
50
  {
43
- title: 'Domains',
51
+ label: 'Domains',
44
52
  count: domains.length,
45
- description: 'Business domains',
46
53
  href: buildUrl('/discover/domains'),
47
- badgeBg: 'bg-[rgb(var(--ec-badge-domain-bg))]',
48
- badgeText: 'text-[rgb(var(--ec-badge-domain-text))]',
49
- glowColor: 'var(--ec-badge-domain-text)',
50
- emptyText: 'No domains yet',
51
- addHref: 'https://www.eventcatalog.dev/docs/domains',
54
+ emptyHref: 'https://www.eventcatalog.dev/docs/domains',
55
+ tone: '250 204 21', // amber-400
52
56
  },
53
57
  {
54
- title: 'Services',
58
+ label: 'Services',
55
59
  count: services.length,
56
- description: 'Documented services',
57
60
  href: buildUrl('/discover/services'),
58
- badgeBg: 'bg-[rgb(var(--ec-badge-service-bg))]',
59
- badgeText: 'text-[rgb(var(--ec-badge-service-text))]',
60
- glowColor: 'var(--ec-badge-service-text)',
61
- emptyText: 'No services yet',
62
- addHref: 'https://www.eventcatalog.dev/docs/services',
61
+ emptyHref: 'https://www.eventcatalog.dev/docs/services',
62
+ tone: '244 114 182', // pink-400
63
63
  },
64
64
  {
65
- title: 'Messages',
65
+ label: 'Messages',
66
66
  count: messages.length,
67
- description: 'Events, commands & queries',
68
67
  href: buildUrl('/discover/events'),
69
- badgeBg: 'bg-[rgb(var(--ec-badge-message-bg))]',
70
- badgeText: 'text-[rgb(var(--ec-badge-message-text))]',
71
- glowColor: 'var(--ec-badge-message-text)',
72
- emptyText: 'No messages yet',
73
- addHref: 'https://www.eventcatalog.dev/docs/messages',
68
+ emptyHref: 'https://www.eventcatalog.dev/docs/messages',
69
+ tone: '167 139 250', // violet-400
74
70
  },
75
71
  {
76
- title: 'Flows',
72
+ label: 'Flows',
77
73
  count: flows.length,
78
- description: 'Business flows',
79
74
  href: buildUrl('/discover/flows'),
80
- badgeBg: 'bg-[rgb(var(--ec-badge-query-bg))]',
81
- badgeText: 'text-[rgb(var(--ec-badge-query-text))]',
82
- glowColor: 'var(--ec-badge-query-text)',
83
- emptyText: 'No flows yet',
84
- addHref: 'https://www.eventcatalog.dev/docs/flows',
75
+ emptyHref: 'https://www.eventcatalog.dev/docs/flows',
76
+ tone: '94 234 212', // teal-300
85
77
  },
86
78
  ];
87
79
 
88
- const quickActions = [
80
+ interface ExploreCard {
81
+ title: string;
82
+ description: string;
83
+ icon: any;
84
+ href: string;
85
+ external?: boolean;
86
+ /** When true, renders as the lead "feature" card with extra width and CTA styling. */
87
+ feature?: boolean;
88
+ tone: string; // RGB triple for the icon tile
89
+ }
90
+
91
+ const exploreCards: ExploreCard[] = [
89
92
  {
90
93
  title: 'Documentation',
91
- description: 'Explore all your events, commands, queries, and services in one place.',
94
+ description: 'Browse every domain, service, message, and flow your teams have published.',
92
95
  icon: BookOpenText,
93
96
  href: getDefaultUrl('docs', 'domains'),
94
- iconBg: 'bg-blue-50 dark:bg-blue-500/10',
95
- iconColor: 'text-blue-600 dark:text-blue-400',
96
- span: 'lg:col-span-2',
97
+ feature: true,
98
+ tone: '96 165 250', // blue-400
97
99
  },
98
100
  {
99
101
  title: 'Visualizer',
100
- description: 'Visualize service relationships and message flows across your architecture.',
102
+ description: 'See how services connect message flows across your architecture.',
101
103
  icon: Workflow,
102
104
  href: getDefaultUrl('visualiser', 'domains'),
103
- iconBg: 'bg-[rgb(var(--ec-accent-subtle))]',
104
- iconColor: 'text-[rgb(var(--ec-accent))]',
105
- span: '',
105
+ tone: '167 139 250', // violet-400
106
106
  },
107
107
  {
108
108
  title: 'Discover',
109
- description: 'Quickly find any event, service, or team across your entire catalog.',
109
+ description: 'Search every event, service, and team across the catalog.',
110
110
  icon: TableProperties,
111
111
  href: buildUrl('/discover/events'),
112
- iconBg: 'bg-teal-50 dark:bg-teal-500/10',
113
- iconColor: 'text-teal-600 dark:text-teal-400',
114
- span: '',
112
+ tone: '94 234 212', // teal-300
115
113
  },
116
114
  {
117
115
  title: 'Schema Explorer',
118
116
  description: 'Track schema evolution, compare versions, and catch breaking changes.',
119
117
  icon: FileJson,
120
118
  href: buildUrl('/schemas/explorer'),
121
- iconBg: 'bg-amber-50 dark:bg-amber-500/10',
122
- iconColor: 'text-amber-600 dark:text-amber-400',
123
- span: '',
119
+ tone: '250 204 21', // amber-400
124
120
  },
125
121
  {
126
122
  title: 'Team Directory',
127
- description: 'See who owns what find team contacts and service ownership at a glance.',
123
+ description: 'Find owners, on-call contacts, and the team behind every service.',
128
124
  icon: BookUser,
129
125
  href: buildUrl('/directory/users'),
130
- iconBg: 'bg-orange-50 dark:bg-orange-500/10',
131
- iconColor: 'text-orange-600 dark:text-orange-400',
132
- span: '',
126
+ tone: '251 146 60', // orange-400
133
127
  },
134
128
  {
135
129
  title: 'API & SDK',
136
- description: 'Query and manage your catalog programmatically with a fully-typed SDK.',
130
+ description: 'Programmatic access — query and manage your catalog with a typed SDK.',
137
131
  icon: Code2,
138
132
  href: 'https://www.eventcatalog.dev/docs/sdk',
139
- iconBg: 'bg-indigo-50 dark:bg-indigo-500/10',
140
- iconColor: 'text-indigo-600 dark:text-indigo-400',
141
133
  external: true,
142
- span: 'lg:col-span-2',
134
+ tone: '129 140 248', // indigo-400
143
135
  },
144
136
  ];
145
137
  ---
146
138
 
147
139
  <VerticalSideBarLayout title="EventCatalog" showNestedSideBar={showNestedSideBar}>
148
- <div class="min-h-screen font-inter">
149
- <!-- Hero Section -->
150
- <div class="relative">
151
- <main class="px-0 pt-7 pb-8 max-w-[85em]">
152
- <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
153
- <div>
154
- <h1 class="text-2xl md:text-3xl font-bold mb-1 text-[rgb(var(--ec-page-text))] tracking-tight">
155
- Welcome to <span class="italic text-[rgb(var(--ec-accent))]">{config?.organizationName || 'EventCatalog'}</span>
156
- </h1>
157
- <p class="text-sm text-[rgb(var(--ec-page-text-muted))] leading-relaxed">
158
- {config.tagline || 'Explore and understand your event-driven architecture'}
159
- </p>
160
- </div>
140
+ <div class="ec-home min-h-screen">
141
+ <!-- Hero -->
142
+ <header class="ec-hero">
143
+ <div class="text-[11px] font-semibold uppercase tracking-[0.18em] text-[rgb(var(--ec-accent))]">Catalog</div>
144
+ <div class="mt-3 flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
145
+ <div>
146
+ <h1 class="text-[28px] font-semibold leading-[1.1] tracking-tight text-[rgb(var(--ec-page-text))] md:text-[32px]">
147
+ {config?.organizationName || 'EventCatalog'}
148
+ </h1>
149
+ <p class="mt-2 max-w-2xl text-[14px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]">
150
+ {config.tagline || 'Explore and understand your event-driven architecture.'}
151
+ </p>
152
+ </div>
153
+ <div class="flex items-center gap-2">
154
+ <a
155
+ href={getDefaultUrl('docs', 'domains')}
156
+ class="ec-btn-primary inline-flex items-center gap-1.5 rounded-md bg-[rgb(var(--ec-page-bg))] border border-[rgb(var(--ec-page-border))] px-3.5 py-2 text-[12.5px] font-semibold text-[rgb(var(--ec-page-text-muted))] transition-colors hover:border-[rgb(var(--ec-accent)/0.5)] hover:text-[rgb(var(--ec-accent))]"
157
+ >
158
+ Explore Catalog
159
+ <ArrowRight className="h-3.5 w-3.5" />
160
+ </a>
161
161
  </div>
162
- </main>
163
- </div>
162
+ </div>
163
+ </header>
164
164
 
165
- <!-- Main Content -->
166
- <main class="px-0 pb-8 max-w-[85em]">
167
- <!-- Stat Cards -->
168
- <section class="mb-10">
169
- <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
170
- {
171
- topTiles.map((tile: any) =>
172
- tile.count > 0 ? (
173
- <a
174
- href={tile.href}
175
- class="ec-stat-card group relative overflow-hidden bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] p-5 rounded-xl border transition-all"
176
- style={`--glow-color: rgb(${tile.glowColor}); border-color: rgb(${tile.glowColor} / 0.2);`}
177
- >
178
- <div class="flex items-center justify-between mb-4">
179
- <span
180
- class={`inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-semibold ${tile.badgeBg} ${tile.badgeText}`}
181
- >
182
- {tile.title}
183
- </span>
184
- </div>
185
- <div class="text-3xl font-bold text-[rgb(var(--ec-page-text))] mb-1">{tile.count}</div>
186
- <div class="text-sm text-[rgb(var(--ec-page-text-muted))]">{tile.description}</div>
187
- </a>
165
+ <div class="ec-divider"></div>
166
+
167
+ <!-- Stat strip -->
168
+ <section class="ec-stats">
169
+ {
170
+ statTiles.map((tile) => (
171
+ <a
172
+ href={tile.count > 0 ? tile.href : tile.emptyHref}
173
+ target={tile.count === 0 ? '_blank' : undefined}
174
+ rel={tile.count === 0 ? 'noreferrer' : undefined}
175
+ class="ec-stat group"
176
+ style={`--tone: ${tile.tone};`}
177
+ >
178
+ <div class="flex items-baseline justify-between gap-2">
179
+ <span class="text-[11px] font-medium uppercase tracking-[0.14em] text-[rgb(var(--tone))]">{tile.label}</span>
180
+ {tile.count > 0 ? (
181
+ <ArrowUpRight className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-transform duration-200 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-[rgb(var(--ec-accent))]" />
188
182
  ) : (
189
- <div class="relative overflow-hidden bg-[rgb(var(--ec-content-hover))] p-5 rounded-xl border border-dashed border-[rgb(var(--ec-page-border))]">
190
- <div class="flex items-center justify-between mb-4">
191
- <span class="inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-semibold bg-[rgb(var(--ec-badge-default-bg))] text-[rgb(var(--ec-badge-default-text))]">
192
- {tile.title}
193
- </span>
194
- </div>
195
- <div class="text-sm font-medium text-[rgb(var(--ec-page-text-muted))] mb-2">{tile.emptyText}</div>
196
- <a
197
- href={tile.addHref}
198
- target="_blank"
199
- class="inline-flex items-center gap-1 text-xs font-medium text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]"
200
- >
201
- <PlusIcon className="w-3 h-3" />
202
- Add {tile.title.toLowerCase()}
203
- </a>
204
- </div>
205
- )
206
- )
207
- }
208
- </div>
209
- </section>
183
+ <Plus className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-colors group-hover:text-[rgb(var(--ec-accent))]" />
184
+ )}
185
+ </div>
186
+ <div class="mt-3 flex items-baseline gap-2">
187
+ <span class="font-mono text-[34px] font-semibold leading-none tracking-tight text-[rgb(var(--ec-page-text))]">
188
+ {tile.count}
189
+ </span>
190
+ {tile.count === 0 && <span class="text-[12px] text-[rgb(var(--ec-page-text-muted))]">— add some</span>}
191
+ </div>
192
+ </a>
193
+ ))
194
+ }
195
+ </section>
210
196
 
211
- <!-- Explore Section - Full Width -->
212
- <section class="mb-10">
213
- <div class="flex items-center gap-4 mb-4">
214
- <h2 class="text-sm font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))] flex-shrink-0">
215
- Explore
216
- </h2>
217
- <div class="flex-1 h-px bg-[rgb(var(--ec-page-border))]"></div>
218
- </div>
219
- <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
220
- {
221
- quickActions.map((action: any) => (
222
- <a
223
- href={action.href}
224
- target={action.external ? '_blank' : undefined}
225
- class={`ec-stat-card group flex flex-col bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] p-6 rounded-xl border border-[rgb(var(--ec-page-border))] hover:border-[rgb(var(--ec-accent)/0.5)] transition-all min-h-[160px] ${action.span}`}
226
- style="--glow-color: rgb(var(--ec-accent));"
227
- >
228
- <div class="flex items-center gap-3 mb-3">
229
- <div class={`${action.iconBg} p-2.5 rounded-lg`}>
230
- <action.icon className={`w-5 h-5 ${action.iconColor}`} />
231
- </div>
232
- <span class="font-semibold text-[rgb(var(--ec-page-text))] flex items-center gap-1.5">
233
- {action.title}
234
- {action.external && (
235
- <svg
236
- class="w-3.5 h-3.5 text-[rgb(var(--ec-icon-color))]"
237
- fill="none"
238
- stroke="currentColor"
239
- viewBox="0 0 24 24"
240
- >
241
- <path
242
- stroke-linecap="round"
243
- stroke-linejoin="round"
244
- stroke-width="2"
245
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
246
- />
247
- </svg>
248
- )}
249
- </span>
250
- </div>
251
- <p class="text-sm text-[rgb(var(--ec-page-text-muted))] leading-relaxed">{action.description}</p>
252
- </a>
253
- ))
254
- }
255
- </div>
256
- </section>
197
+ <!-- Eyebrow + Explore grid -->
198
+ <section class="mt-12">
199
+ <div class="ec-section-eyebrow">
200
+ <span class="text-[11px] font-semibold uppercase tracking-[0.18em] text-[rgb(var(--ec-accent))]">Explore</span>
201
+ <span class="ec-section-rule"></span>
202
+ <span class="font-mono text-[11px] text-[rgb(var(--ec-page-text-muted)/0.7)]">{exploreCards.length} sections</span>
203
+ </div>
257
204
 
258
- <!-- Resources & Community - Compact Footer Style -->
259
- <section class="border-t border-[rgb(var(--ec-page-border))] pt-8 pb-4">
260
- <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-6">
261
- <div class="flex flex-wrap items-center gap-x-6 gap-y-3">
262
- <a
263
- href="https://www.eventcatalog.dev/docs/development/getting-started/introduction"
264
- target="_blank"
265
- class="text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
266
- >
267
- Getting Started
268
- </a>
269
- <a
270
- href="https://www.eventcatalog.dev/integrations"
271
- target="_blank"
272
- class="text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
273
- >
274
- Integrations
275
- </a>
276
- <a
277
- href="https://www.eventcatalog.dev/docs"
278
- target="_blank"
279
- class="text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
280
- >
281
- Documentation
282
- </a>
283
- </div>
284
- <div class="flex items-center gap-4">
285
- <a
286
- href="https://discord.gg/3rjaZMmrAm"
287
- target="_blank"
288
- class="flex items-center gap-2 text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
289
- title="Join Discord"
290
- >
291
- <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
292
- <path
293
- d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"
294
- ></path>
295
- </svg>
296
- <span class="hidden sm:inline">Discord</span>
297
- </a>
205
+ <div class="ec-explore-grid mt-4">
206
+ {
207
+ exploreCards.map((card) => (
298
208
  <a
299
- href="https://github.com/event-catalog/eventcatalog"
300
- target="_blank"
301
- class="flex items-center gap-2 text-sm text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
302
- title="GitHub"
209
+ href={card.href}
210
+ target={card.external ? '_blank' : undefined}
211
+ rel={card.external ? 'noreferrer' : undefined}
212
+ class:list={['ec-card group', card.feature ? 'ec-card--feature' : '']}
213
+ style={`--tone: ${card.tone};`}
303
214
  >
304
- <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
305
- <path
306
- fill-rule="evenodd"
307
- d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
308
- clip-rule="evenodd"></path>
309
- </svg>
310
- <span class="hidden sm:inline">GitHub</span>
215
+ <div class="flex items-start justify-between gap-3">
216
+ <div class="ec-card-icon">
217
+ <card.icon className="h-4 w-4" />
218
+ </div>
219
+ <ArrowUpRight className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))] transition-transform duration-200 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-[rgb(var(--ec-accent))]" />
220
+ </div>
221
+ <h3 class="mt-4 text-[15px] font-semibold tracking-tight text-[rgb(var(--ec-page-text))]">{card.title}</h3>
222
+ <p class="mt-1.5 text-[13px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]">{card.description}</p>
311
223
  </a>
312
- </div>
313
- </div>
314
- </section>
315
- </main>
224
+ ))
225
+ }
226
+ </div>
227
+ </section>
316
228
  </div>
317
229
  </VerticalSideBarLayout>
318
230
 
319
231
  <style is:global>
320
- .ec-stat-card {
232
+ .ec-home {
233
+ /* Negate the layout wrapper's horizontal padding so the homepage controls its own. */
234
+ margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1);
235
+ margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1);
236
+ padding: 2rem 2rem 0;
237
+ }
238
+ .ec-hero {
239
+ padding-bottom: 1.5rem;
240
+ }
241
+ .ec-divider {
242
+ height: 1px;
243
+ background: linear-gradient(
244
+ to right,
245
+ transparent,
246
+ rgb(var(--ec-page-border)) 12%,
247
+ rgb(var(--ec-page-border)) 88%,
248
+ transparent
249
+ );
250
+ margin: 0.25rem 0 1.5rem;
251
+ }
252
+ .ec-stats {
253
+ display: grid;
254
+ grid-template-columns: repeat(2, minmax(0, 1fr));
255
+ gap: 0.75rem;
256
+ }
257
+ @media (min-width: 768px) {
258
+ .ec-stats {
259
+ grid-template-columns: repeat(4, minmax(0, 1fr));
260
+ }
261
+ }
262
+ .ec-stat {
321
263
  position: relative;
264
+ display: flex;
265
+ flex-direction: column;
266
+ overflow: hidden;
267
+ border: 1px solid rgb(var(--ec-page-border));
268
+ border-radius: 0.75rem;
269
+ background:
270
+ radial-gradient(80% 100% at 0% 0%, rgb(var(--tone) / 0.05), transparent 60%), rgb(var(--ec-card-bg, var(--ec-page-bg)));
271
+ padding: 1rem 1.1rem 1.1rem;
272
+ transition:
273
+ border-color 200ms,
274
+ transform 200ms,
275
+ box-shadow 200ms;
276
+ text-decoration: none;
322
277
  }
323
- .ec-stat-card::before {
324
- content: '';
325
- position: absolute;
326
- inset: 0;
327
- border-radius: inherit;
328
- transition: opacity 0.3s ease;
329
- opacity: 0;
330
- pointer-events: none;
331
- z-index: 0;
278
+ .ec-stat:hover {
279
+ border-color: rgb(var(--ec-accent) / 0.5);
280
+ transform: translateY(-1px);
332
281
  }
333
- /* Dark mode: radial glow that follows cursor */
334
- :root[data-theme='dark'] .ec-stat-card::before {
335
- background: radial-gradient(400px circle at var(--mouse-x, 50%) var(--mouse-y, 50%), var(--glow-color) 0%, transparent 70%);
282
+
283
+ .ec-section-eyebrow {
284
+ display: flex;
285
+ align-items: center;
286
+ gap: 0.75rem;
336
287
  }
337
- :root[data-theme='dark'] .ec-stat-card:hover::before {
338
- opacity: 0.15;
288
+ .ec-section-rule {
289
+ flex: 1;
290
+ height: 1px;
291
+ background: linear-gradient(to right, rgb(var(--ec-accent) / 0.4), rgb(var(--ec-page-border)) 30%);
292
+ }
293
+
294
+ /* Explore grid: bordered cells with breathing room between them. */
295
+ .ec-explore-grid {
296
+ display: grid;
297
+ grid-template-columns: repeat(1, minmax(0, 1fr));
298
+ gap: 1rem;
339
299
  }
340
- /* Light mode: subtle solid background */
341
- :root:not([data-theme='dark']) .ec-stat-card::before,
342
- :root[data-theme='light'] .ec-stat-card::before {
343
- background: rgb(var(--ec-content-hover));
300
+ @media (min-width: 640px) {
301
+ .ec-explore-grid {
302
+ grid-template-columns: repeat(2, minmax(0, 1fr));
303
+ }
344
304
  }
345
- :root:not([data-theme='dark']) .ec-stat-card:hover::before,
346
- :root[data-theme='light'] .ec-stat-card:hover::before {
347
- opacity: 1;
305
+ @media (min-width: 1024px) {
306
+ .ec-explore-grid {
307
+ grid-template-columns: repeat(3, minmax(0, 1fr));
308
+ }
348
309
  }
349
- .ec-stat-card > * {
310
+
311
+ .ec-card {
350
312
  position: relative;
351
- z-index: 1;
313
+ display: flex;
314
+ flex-direction: column;
315
+ padding: 1.5rem 1.5rem 1.4rem;
316
+ text-decoration: none;
317
+ border: 1px solid rgb(var(--ec-page-border));
318
+ border-radius: 0.875rem;
319
+ background: rgb(var(--ec-card-bg, var(--ec-page-bg)));
320
+ transition:
321
+ background 200ms,
322
+ border-color 200ms;
323
+ min-height: 9.5rem;
324
+ }
325
+ .ec-card:hover {
326
+ background: rgb(var(--ec-page-bg) / 0.4);
327
+ border-color: rgb(var(--ec-accent) / 0.5);
328
+ }
329
+
330
+ .ec-card--feature {
331
+ background:
332
+ radial-gradient(60% 90% at 0% 0%, rgb(var(--tone) / 0.07), transparent 60%), rgb(var(--ec-card-bg, var(--ec-page-bg)));
333
+ }
334
+ .ec-card--feature:hover {
335
+ background: radial-gradient(60% 90% at 0% 0%, rgb(var(--ec-accent) / 0.12), transparent 60%), rgb(var(--ec-page-bg) / 0.4);
352
336
  }
353
- </style>
354
337
 
355
- <script>
356
- document.querySelectorAll('.ec-stat-card').forEach((card) => {
357
- card.addEventListener('mousemove', (e) => {
358
- const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
359
- const x = (e as MouseEvent).clientX - rect.left;
360
- const y = (e as MouseEvent).clientY - rect.top;
361
- (e.currentTarget as HTMLElement).style.setProperty('--mouse-x', `${x}px`);
362
- (e.currentTarget as HTMLElement).style.setProperty('--mouse-y', `${y}px`);
363
- });
364
- });
365
- </script>
338
+ .ec-card-icon {
339
+ display: inline-flex;
340
+ height: 2.25rem;
341
+ width: 2.25rem;
342
+ align-items: center;
343
+ justify-content: center;
344
+ border-radius: 0.5rem;
345
+ background: rgb(var(--tone) / 0.12);
346
+ color: rgb(var(--tone));
347
+ transition:
348
+ background 200ms,
349
+ color 200ms;
350
+ }
351
+ .ec-card:hover .ec-card-icon {
352
+ background: rgb(var(--ec-accent) / 0.2);
353
+ color: rgb(var(--ec-accent));
354
+ }
355
+ .ec-card--feature .ec-card-icon {
356
+ height: 2.5rem;
357
+ width: 2.5rem;
358
+ border-radius: 0.625rem;
359
+ }
360
+ </style>