@eventcatalog/core 2.6.3 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/astro.config.mjs +0 -6
- package/package.json +1 -1
- package/public/icons/youtube.svg +1 -0
- package/src/components/Header.astro +81 -31
- package/src/components/MDX/NodeGraph/Nodes/Command.tsx +2 -2
- package/src/components/MDX/NodeGraph/Nodes/Event.tsx +2 -2
- package/src/components/MDX/NodeGraph/Nodes/Step.tsx +0 -2
- package/src/components/Tables/columns/MessageTableColumns.tsx +3 -11
- package/src/components/Tables/columns/ServiceTableColumns.tsx +5 -4
- package/src/layouts/CustomDocsPageLayout.astro +2 -2
- package/src/layouts/DiscoverLayout.astro +3 -4
- package/src/layouts/DocsLayout.astro +3 -3
- package/src/layouts/Footer.astro +8 -1
- package/src/layouts/PlainPage.astro +2 -2
- package/src/layouts/VisualiserLayout.astro +103 -34
- package/src/pages/discover/[type]/index.astro +18 -26
- package/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +3 -3
- package/src/pages/docs/[type]/[id]/[version]/index.astro +4 -4
- package/src/pages/docs/[type]/[id]/[version]/spec/index.astro +50 -11
- package/src/pages/index.astro +168 -0
- package/tailwind.config.mjs +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @eventcatalog/core
|
|
2
2
|
|
|
3
|
+
## 2.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 515b01f: feat(core): added ability to full screen visuals, new icons for messages and new landing page
|
|
8
|
+
|
|
9
|
+
## 2.6.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 0459eec: chore(core): fixed styled for openapi pages
|
|
14
|
+
|
|
3
15
|
## 2.6.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/astro.config.mjs
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 -3 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>youtube [#168]</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Dribbble-Light-Preview" transform="translate(-300.000000, -7442.000000)" fill="#000000"> <g id="icons" transform="translate(56.000000, 160.000000)"> <path d="M251.988432,7291.58588 L251.988432,7285.97425 C253.980638,7286.91168 255.523602,7287.8172 257.348463,7288.79353 C255.843351,7289.62824 253.980638,7290.56468 251.988432,7291.58588 M263.090998,7283.18289 C262.747343,7282.73013 262.161634,7282.37809 261.538073,7282.26141 C259.705243,7281.91336 248.270974,7281.91237 246.439141,7282.26141 C245.939097,7282.35515 245.493839,7282.58153 245.111335,7282.93357 C243.49964,7284.42947 244.004664,7292.45151 244.393145,7293.75096 C244.556505,7294.31342 244.767679,7294.71931 245.033639,7294.98558 C245.376298,7295.33761 245.845463,7295.57995 246.384355,7295.68865 C247.893451,7296.0008 255.668037,7296.17532 261.506198,7295.73552 C262.044094,7295.64178 262.520231,7295.39147 262.895762,7295.02447 C264.385932,7293.53455 264.28433,7285.06174 263.090998,7283.18289" id="youtube-[#168]"> </path> </g> </g> </g> </g></svg>
|
|
@@ -21,47 +21,65 @@ const navItems = [
|
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
const logo = {
|
|
24
|
-
src: ('/' + (catalog?.logo?.src || 'logo.png')).replace(/^\/+/, '/'),
|
|
24
|
+
src: ('/' + (catalog?.logo?.src || 'logo.png')).replace(/^\/+/, '/'),
|
|
25
25
|
alt: catalog?.logo?.alt || 'Event Catalog',
|
|
26
26
|
text: catalog?.logo?.text || 'EventCatalog',
|
|
27
27
|
};
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
<nav class="
|
|
31
|
-
<div class="
|
|
32
|
-
<div class="
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
30
|
+
<nav id="eventcatalog-header" class="fixed top-0 left-0 right-0 z-20 bg-white border-b border-gray-200 py-4 font-bold text-xl">
|
|
31
|
+
<div class="max-w-[120em] mx-auto px-4 sm:px-6 lg:px-8 xxl:max-w-[96em]">
|
|
32
|
+
<div class="flex justify-between items-center">
|
|
33
|
+
<div class="flex-shrink-0 flex items-center w-1/3">
|
|
34
|
+
<a href={buildUrl(catalog.landingPage || '/')} class="flex space-x-2 items-center">
|
|
35
|
+
{logo.src && <img alt={logo.alt} src={buildUrl(logo.src, true)} class="w-8 h-8" />}
|
|
36
|
+
{logo.text && <span class="hidden sm:inline-block text-[1em]">{logo.text}</span>}
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div class="hidden lg:block flex-grow mx-4 w-1/3">
|
|
41
|
+
<Search />
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="hidden md:block w-1/3">
|
|
45
|
+
<ul class="flex space-x-8 justify-end">
|
|
46
|
+
{
|
|
47
|
+
navItems.map((item) => {
|
|
48
|
+
const isActive = currentPath.includes(item.href);
|
|
49
|
+
return (
|
|
50
|
+
<li class={`font-light ${isActive ? 'border-b-2 border-purple-500' : ''}`}>
|
|
51
|
+
<a href={item.href}>{item.label}</a>
|
|
52
|
+
</li>
|
|
53
|
+
);
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
</ul>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="md:hidden">
|
|
60
|
+
<button
|
|
61
|
+
id="menu-toggle"
|
|
62
|
+
type="button"
|
|
63
|
+
class="text-gray-500 hover:text-gray-600 focus:outline-none focus:text-gray-600"
|
|
64
|
+
aria-label="Toggle menu"
|
|
65
|
+
>
|
|
66
|
+
<svg viewBox="0 0 24 24" class="h-6 w-6 fill-current">
|
|
67
|
+
<path
|
|
68
|
+
fill-rule="evenodd"
|
|
69
|
+
d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"
|
|
70
|
+
></path>
|
|
71
|
+
</svg>
|
|
72
|
+
</button>
|
|
56
73
|
</div>
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div id="mobile-menu" class="md:hidden hidden mt-4">
|
|
77
|
+
<ul class="flex flex-col space-y-8 my-4 mb-8">
|
|
60
78
|
{
|
|
61
79
|
navItems.map((item) => {
|
|
62
80
|
const isActive = currentPath.includes(item.href);
|
|
63
81
|
return (
|
|
64
|
-
<li class={`font-light ${isActive ? '
|
|
82
|
+
<li class={`font-light ${isActive ? 'font-bold text-purple-500' : ''}`}>
|
|
65
83
|
<a href={item.href}>{item.label}</a>
|
|
66
84
|
</li>
|
|
67
85
|
);
|
|
@@ -71,3 +89,35 @@ const logo = {
|
|
|
71
89
|
</div>
|
|
72
90
|
</div>
|
|
73
91
|
</nav>
|
|
92
|
+
|
|
93
|
+
<div id="eventcatalog-header-spacer" class="h-20"></div>
|
|
94
|
+
<!-- Spacer to prevent content from being hidden under the fixed header -->
|
|
95
|
+
|
|
96
|
+
<script>
|
|
97
|
+
const menuToggle = document.getElementById('menu-toggle');
|
|
98
|
+
const mobileMenu = document.getElementById('mobile-menu');
|
|
99
|
+
|
|
100
|
+
if (menuToggle && mobileMenu) {
|
|
101
|
+
menuToggle.addEventListener('click', () => {
|
|
102
|
+
mobileMenu.classList.toggle('hidden');
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<style>
|
|
108
|
+
@media (max-width: 768px) {
|
|
109
|
+
nav {
|
|
110
|
+
transition: all 0.3s ease-out;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#mobile-menu {
|
|
114
|
+
transition: all 0.3s ease-out;
|
|
115
|
+
max-height: 0;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#mobile-menu:not(.hidden) {
|
|
120
|
+
max-height: 500px; /* Adjust this value as needed */
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatBubbleLeftIcon } from '@heroicons/react/16/solid';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
3
|
import { Handle } from 'reactflow';
|
|
4
4
|
|
|
@@ -33,7 +33,7 @@ export default function CommandNode({ data, sourcePosition, targetPosition }: an
|
|
|
33
33
|
`border-r-[1px] border-blue-500`
|
|
34
34
|
)}
|
|
35
35
|
>
|
|
36
|
-
<
|
|
36
|
+
<ChatBubbleLeftIcon className="w-4 h-4 opacity-90 text-white absolute top-1 " />
|
|
37
37
|
{mode === 'full' && (
|
|
38
38
|
<span className="rotate -rotate-90 w-1/2 text-center absolute bottom-1 text-[9px] text-white font-bold uppercase tracking-[3px] ">
|
|
39
39
|
Command
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BoltIcon } from '@heroicons/react/16/solid';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
3
|
import { Handle } from 'reactflow';
|
|
4
4
|
|
|
@@ -33,7 +33,7 @@ export default function EventNode({ data, sourcePosition, targetPosition }: any)
|
|
|
33
33
|
`border-r-[1px] border-orange-500`
|
|
34
34
|
)}
|
|
35
35
|
>
|
|
36
|
-
<
|
|
36
|
+
<BoltIcon className="w-4 h-4 opacity-90 text-white absolute top-1 " />
|
|
37
37
|
{mode === 'full' && (
|
|
38
38
|
<span className="rotate -rotate-90 w-1/2 text-center absolute bottom-1 text-[9px] text-white font-bold uppercase tracking-[3px] ">
|
|
39
39
|
Event
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ServerIcon } from '@heroicons/react/24/solid';
|
|
1
|
+
import { ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/solid';
|
|
3
2
|
import { createColumnHelper } from '@tanstack/react-table';
|
|
4
3
|
import type { CollectionMessageTypes } from '@types';
|
|
5
4
|
import type { CollectionEntry } from 'astro:content';
|
|
@@ -17,6 +16,7 @@ export const columns = () => [
|
|
|
17
16
|
const messageRaw = info.row.original;
|
|
18
17
|
const type = useMemo(() => messageRaw.collection.slice(0, -1), [messageRaw.collection]);
|
|
19
18
|
const color = type === 'event' ? 'orange' : 'blue';
|
|
19
|
+
const Icon = type === 'event' ? BoltIcon : ChatBubbleLeftIcon;
|
|
20
20
|
return (
|
|
21
21
|
<div className=" group ">
|
|
22
22
|
<a
|
|
@@ -26,7 +26,7 @@ export const columns = () => [
|
|
|
26
26
|
<div className={`flex items-center border border-gray-300 shadow-sm rounded-md group-hover:border-${color}-400`}>
|
|
27
27
|
<span className="flex items-center">
|
|
28
28
|
<span className={`bg-${color}-500 group-hover:bg-${color}-600 h-full rounded-tl rounded-bl p-1`}>
|
|
29
|
-
<
|
|
29
|
+
<Icon className="h-4 w-4 text-white" />
|
|
30
30
|
</span>
|
|
31
31
|
<span className="leading-none px-2 group-hover:underline group-hover:text-purple-500 font-light">
|
|
32
32
|
{messageRaw.data.name} (v{messageRaw.data.version})
|
|
@@ -42,14 +42,6 @@ export const columns = () => [
|
|
|
42
42
|
},
|
|
43
43
|
filterFn: filterByName,
|
|
44
44
|
}),
|
|
45
|
-
// columnHelper.accessor('data.version', {
|
|
46
|
-
// header: () => <span>Version</span>,
|
|
47
|
-
// cell: (info) => {
|
|
48
|
-
// const message = info.row.original;
|
|
49
|
-
// return <div className="text-left">{`v${info.getValue()} ${message.data.latestVersion === message.data.version ? '(latest)': ''}`}</div>
|
|
50
|
-
// },
|
|
51
|
-
// footer: (info) => info.column.id,
|
|
52
|
-
// }),
|
|
53
45
|
columnHelper.accessor('data.summary', {
|
|
54
46
|
id: 'summary',
|
|
55
47
|
header: () => 'Summary',
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ServerIcon } from '@heroicons/react/24/solid';
|
|
1
|
+
import { ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/solid';
|
|
3
2
|
import { createColumnHelper } from '@tanstack/react-table';
|
|
4
3
|
import type { CollectionEntry } from 'astro:content';
|
|
5
4
|
import { useMemo } from 'react';
|
|
@@ -75,6 +74,7 @@ export const columns = () => [
|
|
|
75
74
|
{receives.map((consumer: any) => {
|
|
76
75
|
const type = consumer.collection.slice(0, -1);
|
|
77
76
|
const color = type === 'event' ? 'orange' : 'blue';
|
|
77
|
+
const Icon = type === 'event' ? BoltIcon : ChatBubbleLeftIcon;
|
|
78
78
|
return (
|
|
79
79
|
<li key={consumer.data.id} className="py-1 group font-light ">
|
|
80
80
|
<a
|
|
@@ -84,7 +84,7 @@ export const columns = () => [
|
|
|
84
84
|
<div className={`flex items-center border border-gray-300 shadow-sm rounded-md`}>
|
|
85
85
|
<span className="flex items-center">
|
|
86
86
|
<span className={`bg-${color}-500 h-full rounded-tl rounded-bl p-1`}>
|
|
87
|
-
<
|
|
87
|
+
<Icon className="h-4 w-4 text-white" />
|
|
88
88
|
</span>
|
|
89
89
|
<span className="leading-none px-2 group-hover:underline ">
|
|
90
90
|
{consumer.data.name} (v{consumer.data.version})
|
|
@@ -117,6 +117,7 @@ export const columns = () => [
|
|
|
117
117
|
{sends.map((consumer: any) => {
|
|
118
118
|
const type = consumer.collection.slice(0, -1);
|
|
119
119
|
const color = type === 'event' ? 'orange' : 'blue';
|
|
120
|
+
const Icon = type === 'event' ? BoltIcon : ChatBubbleLeftIcon;
|
|
120
121
|
return (
|
|
121
122
|
<li key={consumer.data.id} className="py-1 group font-light">
|
|
122
123
|
<a
|
|
@@ -126,7 +127,7 @@ export const columns = () => [
|
|
|
126
127
|
<div className={`flex items-center border border-gray-300 shadow-sm rounded-md`}>
|
|
127
128
|
<span className="flex items-center">
|
|
128
129
|
<span className={`bg-${color}-500 h-full rounded-tl rounded-bl p-1`}>
|
|
129
|
-
<
|
|
130
|
+
<Icon className="h-4 w-4 text-white" />
|
|
130
131
|
</span>
|
|
131
132
|
<span className="leading-none px-2 group-hover:underline ">
|
|
132
133
|
{consumer.data.name} (v{consumer.data.version})
|
|
@@ -20,10 +20,10 @@ import { buildUrl } from '@utils/url-builder';
|
|
|
20
20
|
<title>EventCatalog</title>
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
|
-
<div class="px-10 max-w-[
|
|
23
|
+
<div class="px-10 max-w-[120em] mx-auto">
|
|
24
24
|
<Header />
|
|
25
25
|
|
|
26
|
-
<div class="md:pt-
|
|
26
|
+
<div class="md:pt-4">
|
|
27
27
|
<nav class="hidden sm:flex grow w-56 xl:w-[19em] fixed overflow-y-auto h-full py-2">
|
|
28
28
|
<div class="w-full">
|
|
29
29
|
<SideBar />
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Table } from '@components/Tables/Table';
|
|
3
|
-
import { QueueListIcon, RectangleGroupIcon } from '@heroicons/react/24/outline';
|
|
4
|
-
import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon';
|
|
3
|
+
import { QueueListIcon, RectangleGroupIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
|
|
5
4
|
import ServerIcon from '@heroicons/react/24/outline/ServerIcon';
|
|
6
5
|
import PlainPage from '@layouts/PlainPage.astro';
|
|
7
6
|
import { getCommands } from '@utils/commands';
|
|
@@ -25,7 +24,7 @@ const tabs = [
|
|
|
25
24
|
label: `Events (${events.length})`,
|
|
26
25
|
href: buildUrl('/discover/events'),
|
|
27
26
|
isActive: currentPath === '/discover/events',
|
|
28
|
-
icon:
|
|
27
|
+
icon: BoltIcon,
|
|
29
28
|
activeColor: 'orange',
|
|
30
29
|
enabled: events.length > 0,
|
|
31
30
|
},
|
|
@@ -33,7 +32,7 @@ const tabs = [
|
|
|
33
32
|
label: `Commands (${commands.length})`,
|
|
34
33
|
href: buildUrl('/discover/commands'),
|
|
35
34
|
isActive: currentPath === '/discover/commands',
|
|
36
|
-
icon:
|
|
35
|
+
icon: ChatBubbleLeftIcon,
|
|
37
36
|
activeColor: 'blue',
|
|
38
37
|
enabled: commands.length > 0,
|
|
39
38
|
},
|
|
@@ -17,12 +17,12 @@ import SEO from '../components/Seo.astro';
|
|
|
17
17
|
<SEO title={`EventCatalog | ${title}`} description={description} ogTitle={title} />
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
|
-
<div class="px-10 max-w-[
|
|
20
|
+
<div class="px-10 max-w-[120em] mx-auto">
|
|
21
21
|
<Header />
|
|
22
22
|
|
|
23
|
-
<div
|
|
23
|
+
<div>
|
|
24
24
|
<nav class="hidden sm:flex grow w-56 xl:w-[19em] fixed overflow-y-auto h-full py-2">
|
|
25
|
-
<div class="w-full">
|
|
25
|
+
<div class="w-full pt-4">
|
|
26
26
|
<SideBar />
|
|
27
27
|
</div>
|
|
28
28
|
</nav>
|
package/src/layouts/Footer.astro
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { buildUrl } from '@utils/url-builder';
|
|
3
|
+
const { className } = Astro.props;
|
|
3
4
|
---
|
|
4
5
|
|
|
5
|
-
<footer class=
|
|
6
|
+
<footer class={`py-4 space-y-8 border-t border-gray-300 ${className}`}>
|
|
6
7
|
<div class="flex justify-between items-center py-8 text-gray-500 text-sm font-light">
|
|
7
8
|
<div class="flex space-x-5">
|
|
8
9
|
<a href="https://github.com/event-catalog/eventcatalog" target="_blank"
|
|
@@ -17,6 +18,12 @@ import { buildUrl } from '@utils/url-builder';
|
|
|
17
18
|
style={`mask-image: url("${buildUrl('/icons/x-twitter.svg', true)}"); mask-repeat: no-repeat; mask-position: center center;`}
|
|
18
19
|
></svg></a
|
|
19
20
|
>
|
|
21
|
+
<a href="https://www.youtube.com/@event-catalog" target="_blank"
|
|
22
|
+
><span class="sr-only">x</span><svg
|
|
23
|
+
class="w-5 h-5 bg-gray-400 hover:bg-purple-500 dark:hover:bg-gray-400"
|
|
24
|
+
style={`mask-image: url("${buildUrl('/icons/youtube.svg', true)}"); mask-repeat: no-repeat; mask-position: center center;`}
|
|
25
|
+
></svg></a
|
|
26
|
+
>
|
|
20
27
|
</div>
|
|
21
28
|
<a
|
|
22
29
|
target="_blank"
|
|
@@ -16,10 +16,10 @@ import SEO from '@components/Seo.astro';
|
|
|
16
16
|
<SEO title={`EventCatalog | ${title}`} description={description} ogTitle={title} />
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
|
-
<div class="px-10 max-w-[
|
|
19
|
+
<div class="px-10 max-w-[120em] mx-auto">
|
|
20
20
|
<Header />
|
|
21
21
|
|
|
22
|
-
<div class="md:pt-
|
|
22
|
+
<div class="md:pt-4">
|
|
23
23
|
<div>
|
|
24
24
|
<slot />
|
|
25
25
|
</div>
|
|
@@ -54,43 +54,112 @@ const getColor = (collection: string) => {
|
|
|
54
54
|
<PlainPage title={title} description={description}>
|
|
55
55
|
<div class="flex min-h-full flex-row md:flex-col">
|
|
56
56
|
<div class="mx-auto flex flex-col-reverse md:flex-row w-full items-start">
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
57
|
+
<div>
|
|
58
|
+
<aside
|
|
59
|
+
class="md:sticky mt-8 md:mt-0 top-0 w-full md:w-60 xl:w-[19em] shrink-0 lg:block font-light pr-10"
|
|
60
|
+
id="visualiser-navigation"
|
|
61
|
+
>
|
|
62
|
+
{
|
|
63
|
+
Object.keys(navigation).map((key: any) => {
|
|
64
|
+
const items = navigation[key]
|
|
65
|
+
.map((item: any) => {
|
|
66
|
+
const isCurrent = currentPath.includes(`${item.collection}/${item.data.id}/${item.data.version}`);
|
|
67
|
+
const isLatest = item.data.version === item.data.latestVersion;
|
|
68
|
+
if (!isLatest) return null;
|
|
69
|
+
return {
|
|
70
|
+
label: item.data.name,
|
|
71
|
+
version: item.data.version,
|
|
72
|
+
color: getColor(item.collection),
|
|
73
|
+
href: buildUrl(`/visualiser/${item.collection}/${item.data.id}/${item.data.version}`),
|
|
74
|
+
active: isCurrent,
|
|
75
|
+
};
|
|
76
|
+
})
|
|
77
|
+
.filter((n: any) => n !== null);
|
|
78
|
+
return (
|
|
79
|
+
<BasicList
|
|
80
|
+
title={`${key} (${navigation[key].length})`}
|
|
81
|
+
items={items}
|
|
82
|
+
emptyMessage="Nothing to show"
|
|
83
|
+
color="gray"
|
|
84
|
+
client:load
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
</aside>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<main class="flex-1 h-full w-full relative">
|
|
93
|
+
<button
|
|
94
|
+
id="fullscreen-toggle"
|
|
95
|
+
class="absolute top-[1em] z-40 left-5 bg-white hover:bg-gray-100/50 border border-gray-200 hover:text-purple-500 text-gray-800 font-semibold py-2 px-4 rounded-lg transition duration-300 ease-in-out flex items-center space-x-2 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75"
|
|
96
|
+
>
|
|
97
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
98
|
+
<path
|
|
99
|
+
stroke-linecap="round"
|
|
100
|
+
stroke-linejoin="round"
|
|
101
|
+
stroke-width="2"
|
|
102
|
+
d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path>
|
|
103
|
+
</svg>
|
|
104
|
+
<span>Toggle Fullscreen</span>
|
|
105
|
+
</button>
|
|
91
106
|
<slot />
|
|
92
107
|
</main>
|
|
93
108
|
</div>
|
|
94
109
|
<ViewTransitions />
|
|
95
110
|
</div>
|
|
96
111
|
</PlainPage>
|
|
112
|
+
|
|
113
|
+
<script>
|
|
114
|
+
function setupSidebarToggle() {
|
|
115
|
+
const sidebar = document.getElementById('visualiser-navigation');
|
|
116
|
+
const toggleButton = document.getElementById('fullscreen-toggle');
|
|
117
|
+
const eventCatalogHeader = document.getElementById('eventcatalog-header');
|
|
118
|
+
const eventCatalogHeaderSpacer = document.getElementById('eventcatalog-header-spacer');
|
|
119
|
+
let isSidebarVisible = true;
|
|
120
|
+
|
|
121
|
+
if (!sidebar || !toggleButton) return;
|
|
122
|
+
|
|
123
|
+
function toggleSidebar() {
|
|
124
|
+
isSidebarVisible = !isSidebarVisible;
|
|
125
|
+
if (sidebar) sidebar.style.display = isSidebarVisible ? 'block' : 'none';
|
|
126
|
+
if (eventCatalogHeader) eventCatalogHeader.style.display = isSidebarVisible ? 'block' : 'none';
|
|
127
|
+
if (eventCatalogHeaderSpacer) eventCatalogHeaderSpacer.style.display = isSidebarVisible ? 'block' : 'none';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Remove existing event listener if it exists
|
|
131
|
+
toggleButton.removeEventListener('click', toggleSidebar);
|
|
132
|
+
|
|
133
|
+
// Add the event listener
|
|
134
|
+
toggleButton.addEventListener('click', toggleSidebar);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Run the setup immediately
|
|
138
|
+
setupSidebarToggle();
|
|
139
|
+
|
|
140
|
+
// Re-run the setup after each navigation
|
|
141
|
+
document.addEventListener('astro:page-load', setupSidebarToggle);
|
|
142
|
+
</script>
|
|
143
|
+
|
|
144
|
+
<style>
|
|
145
|
+
#visualiser-navigation {
|
|
146
|
+
transform: translateX(0);
|
|
147
|
+
}
|
|
148
|
+
</style>
|
|
149
|
+
|
|
150
|
+
<style>
|
|
151
|
+
#visualiser-navigation {
|
|
152
|
+
transition:
|
|
153
|
+
transform 0.3s ease-in-out,
|
|
154
|
+
opacity 0.3s ease-in-out;
|
|
155
|
+
transform: translateX(0);
|
|
156
|
+
opacity: 1;
|
|
157
|
+
}
|
|
158
|
+
#visualiser-navigation.hidden {
|
|
159
|
+
transform: translateX(-100%);
|
|
160
|
+
opacity: 0;
|
|
161
|
+
}
|
|
162
|
+
main {
|
|
163
|
+
transition: margin-left 0.3s ease-in-out;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
@@ -1,39 +1,31 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { getEvents } from '@utils/events';
|
|
3
2
|
import DiscoverLayout from '@layouts/DiscoverLayout.astro';
|
|
4
|
-
import type {
|
|
5
|
-
import type { CollectionTypes } from '@types';
|
|
6
|
-
import { getCommands } from '@utils/commands';
|
|
7
|
-
import { getServices } from '@utils/services/services';
|
|
8
|
-
import { getDomains } from '@utils/domains/domains';
|
|
3
|
+
import type { PageTypes } from '@types';
|
|
9
4
|
import { getFlows } from '@utils/flows/flows';
|
|
10
5
|
|
|
6
|
+
import { pageDataLoader } from '@utils/pages/pages';
|
|
7
|
+
type PageTypesWithFlows = PageTypes | 'flows';
|
|
8
|
+
|
|
11
9
|
export async function getStaticPaths() {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
const loaders = {
|
|
11
|
+
...pageDataLoader,
|
|
12
|
+
flows: getFlows,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const itemTypes: PageTypesWithFlows[] = ['events', 'commands', 'services', 'domains', 'flows'];
|
|
16
|
+
const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
return allItems.flatMap((items, index) =>
|
|
19
|
+
items.map((item) => ({
|
|
20
20
|
params: {
|
|
21
|
-
type,
|
|
21
|
+
type: itemTypes[index],
|
|
22
22
|
},
|
|
23
23
|
props: {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
data: items,
|
|
25
|
+
type: itemTypes[index],
|
|
26
26
|
},
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return [
|
|
31
|
-
buildPage('events', events),
|
|
32
|
-
buildPage('commands', commands),
|
|
33
|
-
buildPage('services', services),
|
|
34
|
-
buildPage('domains', domains),
|
|
35
|
-
buildPage('flows', flows),
|
|
36
|
-
];
|
|
27
|
+
}))
|
|
28
|
+
);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
31
|
const { type, data } = Astro.props;
|
|
@@ -4,7 +4,7 @@ import Footer from '@layouts/Footer.astro';
|
|
|
4
4
|
|
|
5
5
|
import type { PageTypes } from '@types';
|
|
6
6
|
import { getChangeLogs } from '@utils/changelogs/changelogs';
|
|
7
|
-
import {
|
|
7
|
+
import { RectangleGroupIcon, ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
|
|
8
8
|
import { pageDataLoader } from '@utils/pages/pages';
|
|
9
9
|
|
|
10
10
|
import { buildUrl } from '@utils/url-builder';
|
|
@@ -59,10 +59,10 @@ const getBadge = () => {
|
|
|
59
59
|
return { backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-400' };
|
|
60
60
|
}
|
|
61
61
|
if (props.collection === 'events') {
|
|
62
|
-
return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon:
|
|
62
|
+
return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-400' };
|
|
63
63
|
}
|
|
64
64
|
if (props.collection === 'commands') {
|
|
65
|
-
return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon:
|
|
65
|
+
return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-400' };
|
|
66
66
|
}
|
|
67
67
|
if (props.collection === 'domains') {
|
|
68
68
|
return {
|
|
@@ -11,7 +11,7 @@ import ServiceSideBar from '@components/SideBars/ServiceSideBar.astro';
|
|
|
11
11
|
import MessageSideBar from '@components/SideBars/MessageSideBar.astro';
|
|
12
12
|
import DomainSideBar from '@components/SideBars/DomainSideBar.astro';
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { QueueListIcon, RectangleGroupIcon, ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
|
|
15
15
|
import type { PageTypes } from '@types';
|
|
16
16
|
|
|
17
17
|
import { buildUrl } from '@utils/url-builder';
|
|
@@ -57,10 +57,10 @@ const getBadge = () => {
|
|
|
57
57
|
return { backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-400' };
|
|
58
58
|
}
|
|
59
59
|
if (props.collection === 'events') {
|
|
60
|
-
return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon:
|
|
60
|
+
return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-400' };
|
|
61
61
|
}
|
|
62
62
|
if (props.collection === 'commands') {
|
|
63
|
-
return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon:
|
|
63
|
+
return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-400' };
|
|
64
64
|
}
|
|
65
65
|
if (props.collection === 'domains') {
|
|
66
66
|
return {
|
|
@@ -118,7 +118,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
118
118
|
<!-- <main class="flex py-8 sm:px-8 docs-layout"> -->
|
|
119
119
|
<div class="flex min-h-screen docs-layout">
|
|
120
120
|
<main class="flex-1 w-full lg:pr-10 md:pt-4">
|
|
121
|
-
<div class="border-b border-gray-200 flex justify-between items-start py-4 md:
|
|
121
|
+
<div class="border-b border-gray-200 flex justify-between items-start py-4 md:pb-6">
|
|
122
122
|
<div>
|
|
123
123
|
<h2 class="text-2xl md:text-4xl font-bold">
|
|
124
124
|
{props.data.name}
|
|
@@ -53,16 +53,24 @@ const fileExists = fs.existsSync(pathOnDisk);
|
|
|
53
53
|
) : (
|
|
54
54
|
<rapi-doc
|
|
55
55
|
spec-url={buildUrl(pathToSpec, true)}
|
|
56
|
-
render-style="table"
|
|
57
56
|
show-header="false"
|
|
58
|
-
allow-authentication="
|
|
59
|
-
allow-try="
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
allow-authentication="true"
|
|
58
|
+
allow-try="true"
|
|
59
|
+
class="relative top-0"
|
|
60
|
+
style={{ height: '100vh', width: '100%', zIndex: 100 }}
|
|
61
|
+
regular-font="ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji"
|
|
63
62
|
schema-style="table"
|
|
64
|
-
|
|
65
|
-
bg-color="#
|
|
63
|
+
default-schema-tab="schema"
|
|
64
|
+
bg-color="#ffffff"
|
|
65
|
+
text-color=""
|
|
66
|
+
nav-bg-color="#fff"
|
|
67
|
+
nav-text-color=""
|
|
68
|
+
nav-hover-bg-color="#fff"
|
|
69
|
+
nav-hover-text-color="#6b21a8"
|
|
70
|
+
nav-accent-color=""
|
|
71
|
+
primary-color="#6b21a8"
|
|
72
|
+
theme="light"
|
|
73
|
+
render-style="read"
|
|
66
74
|
/>
|
|
67
75
|
)
|
|
68
76
|
}
|
|
@@ -76,13 +84,44 @@ const fileExists = fs.existsSync(pathOnDisk);
|
|
|
76
84
|
<style>
|
|
77
85
|
rapi-doc::part(section-servers) {
|
|
78
86
|
/* <<< targets the server div */
|
|
79
|
-
background: #6b5b95;
|
|
80
|
-
|
|
87
|
+
/* background: #6b5b95; */
|
|
88
|
+
border: 2px solid #f1edff;
|
|
89
|
+
color: black;
|
|
81
90
|
margin: 0 24px 0 24px;
|
|
82
91
|
border-radius: 5px;
|
|
83
92
|
}
|
|
84
93
|
rapi-doc::part(label-selected-server) {
|
|
85
94
|
/* <<< targets selected server label */
|
|
86
|
-
color:
|
|
95
|
+
color: black;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
rapi-doc::part(section-navbar-search) {
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 0;
|
|
101
|
+
margin-bottom: 1em;
|
|
102
|
+
}
|
|
103
|
+
rapi-doc::part(section-overview) {
|
|
104
|
+
margin: 0 2em 0 2em;
|
|
105
|
+
padding: 1em 0 1em;
|
|
106
|
+
}
|
|
107
|
+
rapi-doc::part(section-auth) {
|
|
108
|
+
margin: 2em 2em;
|
|
109
|
+
padding: 0;
|
|
110
|
+
}
|
|
111
|
+
rapi-doc::part(section-tag) {
|
|
112
|
+
margin: 2em 2em;
|
|
113
|
+
padding: 0;
|
|
114
|
+
}
|
|
115
|
+
rapi-doc::part(section-tag-title) {
|
|
116
|
+
margin: 0.5em 0 0;
|
|
117
|
+
padding: 0;
|
|
118
|
+
}
|
|
119
|
+
rapi-doc::part(section-operations-in-tag) {
|
|
120
|
+
margin: 1em 2em;
|
|
121
|
+
padding: 0;
|
|
122
|
+
}
|
|
123
|
+
rapi-doc::part(section-navbar) {
|
|
124
|
+
border-right: 1px solid #f1edff;
|
|
125
|
+
padding: 1em 1em 0 0;
|
|
87
126
|
}
|
|
88
127
|
</style>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Footer from '@layouts/Footer.astro';
|
|
3
|
+
import PlainPage from '@layouts/PlainPage.astro';
|
|
4
|
+
import { buildUrl } from '@utils/url-builder';
|
|
5
|
+
import { BoltIcon, ChatBubbleLeftIcon, QueueListIcon, RectangleGroupIcon, ServerIcon } from '@heroicons/react/24/outline';
|
|
6
|
+
|
|
7
|
+
import { getMessages } from '@utils/messages';
|
|
8
|
+
import { getDomains } from '@utils/domains/domains';
|
|
9
|
+
import { getServices } from '@utils/services/services';
|
|
10
|
+
import { getFlows } from '@utils/flows/flows';
|
|
11
|
+
|
|
12
|
+
const { commands = [], events = [] } = await getMessages();
|
|
13
|
+
const domains = await getDomains();
|
|
14
|
+
const services = await getServices();
|
|
15
|
+
const flows = await getFlows();
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<PlainPage title="EventCatalog">
|
|
19
|
+
<body class="min-h-screen">
|
|
20
|
+
<main class="container mx-auto px-6 py-20 max-w-[90em]">
|
|
21
|
+
<section class="text-center mb-8">
|
|
22
|
+
<h1 class="text-5xl font-bold mb-6 text-gray-800">Welcome to <span class="text-purple-600">EventCatalog</span></h1>
|
|
23
|
+
<p class="text-xl mb-8 text-gray-700 max-w-2xl mx-auto font-light">
|
|
24
|
+
Discover and document your event-driven architecture effortlessly. EventCatalog centralizes your events, services, and
|
|
25
|
+
schemas in one place.
|
|
26
|
+
</p>
|
|
27
|
+
</section>
|
|
28
|
+
|
|
29
|
+
<div class="hidden md:block">
|
|
30
|
+
<h2 class="text-center text-xl font-bold">Architecture insights</h2>
|
|
31
|
+
<section class="mb-16 bg-white rounded-xl shadow-lg p-6">
|
|
32
|
+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
|
|
33
|
+
<div class="text-center">
|
|
34
|
+
<div class="flex justify-center mb-2">
|
|
35
|
+
<RectangleGroupIcon className="w-8 h-8 text-yellow-600" />
|
|
36
|
+
</div>
|
|
37
|
+
<div class="text-2xl font-bold text-yellow-600 mb-1">
|
|
38
|
+
<span class="statistic" data-target="5">0</span>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="text-sm text-gray-600">Domains</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="text-center">
|
|
43
|
+
<div class="flex justify-center mb-2">
|
|
44
|
+
<ServerIcon className="w-8 h-8 text-pink-500" />
|
|
45
|
+
</div>
|
|
46
|
+
<div class="text-2xl font-bold text-pink-500 mb-1">
|
|
47
|
+
<span class="statistic" data-target="12">0</span>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="text-sm text-gray-600">Services</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="text-center">
|
|
52
|
+
<div class="flex justify-center mb-2">
|
|
53
|
+
<ChatBubbleLeftIcon className="w-8 h-8 text-blue-500" />
|
|
54
|
+
</div>
|
|
55
|
+
<div class="text-2xl font-bold text-blue-500 mb-1">
|
|
56
|
+
<span class="statistic" data-target="30">0</span>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="text-sm text-gray-600">Commands</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="text-center">
|
|
61
|
+
<div class="flex justify-center mb-2">
|
|
62
|
+
<BoltIcon className="w-8 h-8 text-orange-400" />
|
|
63
|
+
</div>
|
|
64
|
+
<div class="text-2xl font-bold text-orange-400 mb-1">
|
|
65
|
+
<span class="statistic" data-target="20">0</span>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="text-sm text-gray-600">Events</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="text-center">
|
|
71
|
+
<div class="flex justify-center mb-2">
|
|
72
|
+
<QueueListIcon className="w-8 h-8 text-green-800" />
|
|
73
|
+
</div>
|
|
74
|
+
<div class="text-2xl font-bold text-green-800 mb-1">
|
|
75
|
+
<span class="statistic" data-target="8">0</span>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="text-sm text-gray-600">Flows</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</section>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<section class="grid grid-cols-1 md:grid-cols-3 gap-8 mb-16">
|
|
84
|
+
<div
|
|
85
|
+
class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition duration-300 transform hover:-translate-y-1"
|
|
86
|
+
>
|
|
87
|
+
<div class="h-2 bg-blue-400"></div>
|
|
88
|
+
<div class="p-6">
|
|
89
|
+
<h2 class="text-2xl font-semibold mb-4 text-blue-700">Documentation</h2>
|
|
90
|
+
<p class="text-gray-600 mb-4">
|
|
91
|
+
Create and maintain comprehensive documentation for your events, including schemas, examples, and versioning.
|
|
92
|
+
</p>
|
|
93
|
+
<a href={buildUrl('/docs')} class="text-blue-600 hover:text-blue-800 font-semibold">Explore docs →</a>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div
|
|
97
|
+
class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition duration-300 transform hover:-translate-y-1"
|
|
98
|
+
>
|
|
99
|
+
<div class="h-2 bg-teal-400"></div>
|
|
100
|
+
<div class="p-6">
|
|
101
|
+
<h2 class="text-2xl font-semibold mb-4 text-teal-700">Visualiser</h2>
|
|
102
|
+
<p class="text-gray-600 mb-4">
|
|
103
|
+
Transform complex event flows into clear, interactive diagrams. Gain insights at a glance and communicate
|
|
104
|
+
effectively across teams.
|
|
105
|
+
</p>
|
|
106
|
+
<a href={buildUrl('/visualiser')} class="text-teal-600 hover:text-teal-800 font-semibold">Explore visualiser →</a>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div
|
|
111
|
+
class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition duration-300 transform hover:-translate-y-1"
|
|
112
|
+
>
|
|
113
|
+
<div class="h-2 bg-red-700"></div>
|
|
114
|
+
<div class="p-6">
|
|
115
|
+
<h2 class="text-2xl font-semibold mb-4 text-red-700">Discover</h2>
|
|
116
|
+
<p class="text-gray-600 mb-4">
|
|
117
|
+
Dive deep into your event catalog. Search, filter, and analyze your events to gain insights and improve your
|
|
118
|
+
architecture.
|
|
119
|
+
</p>
|
|
120
|
+
<a href={buildUrl('/discover/events')} class="text-red-600 hover:text-red-800 font-semibold">Start exploring →</a>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</section>
|
|
124
|
+
</main>
|
|
125
|
+
|
|
126
|
+
<script define:vars={{ domains, services, commands, events, flows }}>
|
|
127
|
+
function animateStatistics() {
|
|
128
|
+
const statistics = document.querySelectorAll('.statistic');
|
|
129
|
+
statistics.forEach((statistic) => {
|
|
130
|
+
let target;
|
|
131
|
+
switch (statistic.parentElement.nextElementSibling.textContent.trim()) {
|
|
132
|
+
case 'Domains':
|
|
133
|
+
target = domains.length;
|
|
134
|
+
break;
|
|
135
|
+
case 'Services':
|
|
136
|
+
target = services.length;
|
|
137
|
+
break;
|
|
138
|
+
case 'Commands':
|
|
139
|
+
target = commands.length;
|
|
140
|
+
break;
|
|
141
|
+
case 'Events':
|
|
142
|
+
target = events.length;
|
|
143
|
+
break;
|
|
144
|
+
case 'Flows':
|
|
145
|
+
target = flows.length;
|
|
146
|
+
break;
|
|
147
|
+
default:
|
|
148
|
+
target = parseInt(statistic.getAttribute('data-target'));
|
|
149
|
+
}
|
|
150
|
+
let current = 0;
|
|
151
|
+
const increment = target / 50;
|
|
152
|
+
const timer = setInterval(() => {
|
|
153
|
+
current += increment;
|
|
154
|
+
statistic.textContent = Math.round(current);
|
|
155
|
+
if (current >= target) {
|
|
156
|
+
clearInterval(timer);
|
|
157
|
+
statistic.textContent = target;
|
|
158
|
+
}
|
|
159
|
+
}, 20);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
window.addEventListener('load', animateStatistics);
|
|
164
|
+
</script>
|
|
165
|
+
</body>
|
|
166
|
+
</PlainPage>
|
|
167
|
+
|
|
168
|
+
<Footer className="px-10" />
|
package/tailwind.config.mjs
CHANGED