@eventcatalog/core 5.7.1 → 5.7.4

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 (43) 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-GRC67WHC.js → chunk-GOIDVIMH.js} +1 -1
  6. package/dist/{chunk-HZ3XZKUT.js → chunk-L2PFSX4L.js} +1 -1
  7. package/dist/{chunk-36XVRD36.js → chunk-PLTHZFTW.js} +1 -1
  8. package/dist/{chunk-CPF5WE3R.js → chunk-PXYVJK54.js} +1 -1
  9. package/dist/{chunk-AXWTR2FV.js → chunk-RUG7AIT5.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/01-what-is-eventcatalog-assistant.md +8 -0
  13. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +24 -0
  14. package/dist/docs/development/studio/01-introduction.md +2 -1
  15. package/dist/docs/development/studio/04-collaborate-on-a-canvas.md +10 -2
  16. package/dist/docs/development/studio/05-connect-your-agent.md +4 -0
  17. package/dist/docs/development/studio/07-reference.md +40 -7
  18. package/dist/docs/development/studio/draw-with-ai.md +96 -0
  19. package/dist/eventcatalog.cjs +1 -1
  20. package/dist/eventcatalog.js +5 -5
  21. package/dist/generate.cjs +1 -1
  22. package/dist/generate.js +3 -3
  23. package/dist/utils/cli-logger.cjs +1 -1
  24. package/dist/utils/cli-logger.js +2 -2
  25. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +113 -8
  26. package/eventcatalog/src/components/ChatPanel/panel-width.ts +28 -0
  27. package/eventcatalog/src/components/MDX/Steps/Step.astro +4 -2
  28. package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +2 -103
  29. package/eventcatalog/src/components/SchemaExplorer/diff-dark-styles.ts +104 -0
  30. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +71 -71
  31. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +1 -1
  32. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +25 -3
  33. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +1 -1
  34. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +1 -1
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_ChangelogPage.astro +297 -0
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.spec.ts +101 -0
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +76 -47
  38. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +4 -168
  39. package/eventcatalog/src/pages/docs/services/[id]/[version]/changelog/index.astro +14 -0
  40. package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +3 -3
  41. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +112 -28
  42. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +24 -10
  43. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, useCallback, useState, useMemo, memo } from 'react';
1
+ import { useEffect, useRef, useCallback, useState, useMemo, memo, type RefObject } from 'react';
2
2
  import {
3
3
  X,
4
4
  Square,
@@ -28,6 +28,7 @@ import * as Dialog from '@radix-ui/react-dialog';
28
28
  import * as Popover from '@radix-ui/react-popover';
29
29
  import { buildUrl } from '@utils/url-builder';
30
30
  import OfflineReply, { ConfigurationErrorReply, getChatError, offlineReplyText } from './OfflineReply';
31
+ import { clampPanelWidth, MAX_PANEL_WIDTH, MIN_PANEL_WIDTH, PANEL_WIDTH, readPanelWidth, savePanelWidth } from './panel-width';
31
32
  import {
32
33
  ASSISTANT_DRAWING_EVENT,
33
34
  CANVAS_FOCUS_EVENT,
@@ -487,7 +488,15 @@ interface ChatPanelProps {
487
488
  onClose: () => void;
488
489
  }
489
490
 
490
- const PANEL_WIDTH = 400;
491
+ /** The window's width without its scrollbar, which the panel (fixed, on the right) sits inside of (or the window's, where
492
+ * that isn't known) */
493
+ const viewportWidth = () => document.documentElement.clientWidth || window.innerWidth;
494
+
495
+ /** What the panel pushes over to make room for it (looked up each time: ClientRouter navigations swap in new pages) */
496
+ const pageBesidePanel = () =>
497
+ [document.getElementById('eventcatalog-application'), document.getElementById('eventcatalog-header')].filter(
498
+ Boolean
499
+ ) as HTMLElement[];
491
500
 
492
501
  // Staggered fade-in animation styles (delays account for 420ms panel slide)
493
502
  const fadeInStyles = {
@@ -793,6 +802,84 @@ const FlaggedHotspots = memo(({ hotspots }: { hotspots: FlaggedHotspot[] }) => (
793
802
  ));
794
803
  FlaggedHotspots.displayName = 'FlaggedHotspots';
795
804
 
805
+ /** The panel's left edge: dragged to make it wider or narrower (or with the arrow keys), double-clicked back to the default */
806
+ const PanelResizeHandle = memo(
807
+ ({ panel, width, onResize }: { panel: RefObject<HTMLDivElement | null>; width: number; onResize: (width: number) => void }) => {
808
+ // Pressed, and whether it's moved since (a click, or each click of a double click, changes nothing)
809
+ const dragging = useRef<{ moved: boolean } | null>(null);
810
+ const [isDragging, setIsDragging] = useState(false);
811
+ const widthAt = (clientX: number) => clampPanelWidth(viewportWidth() - clientX, viewportWidth());
812
+ // While dragging, the panel and the page beside it are sized here, outside React, so the messages don't re-render
813
+ // on every move (and the page follows the pointer, without its slide)
814
+ const show = (next: number) => {
815
+ if (panel.current) panel.current.style.width = `min(${next}px, 100vw)`;
816
+ pageBesidePanel().forEach((el) => (el.style.paddingRight = `${next}px`));
817
+ };
818
+ const stop = (next: number) => {
819
+ const moved = dragging.current?.moved;
820
+ dragging.current = null;
821
+ setIsDragging(false);
822
+ show(moved ? next : width);
823
+ pageBesidePanel().forEach((el) => (el.style.transition = ''));
824
+ if (moved) onResize(next);
825
+ };
826
+ return (
827
+ <div
828
+ role="separator"
829
+ aria-orientation="vertical"
830
+ aria-label="Resize the assistant"
831
+ aria-valuemin={MIN_PANEL_WIDTH}
832
+ aria-valuemax={MAX_PANEL_WIDTH}
833
+ aria-valuenow={width}
834
+ tabIndex={0}
835
+ title="Drag to resize"
836
+ onPointerDown={(event) => {
837
+ if (event.button !== 0) return;
838
+ event.preventDefault();
839
+ // Keeps pointer events coming while the pointer is over the page (throws if the pointer has gone)
840
+ try {
841
+ event.currentTarget.setPointerCapture(event.pointerId);
842
+ } catch {}
843
+ dragging.current = { moved: false };
844
+ setIsDragging(true);
845
+ pageBesidePanel().forEach((el) => (el.style.transition = 'none'));
846
+ }}
847
+ onPointerMove={(event) => {
848
+ if (!dragging.current) return;
849
+ dragging.current.moved = true;
850
+ show(widthAt(event.clientX));
851
+ }}
852
+ onPointerUp={(event) => dragging.current && stop(widthAt(event.clientX))}
853
+ onPointerCancel={() => {
854
+ if (!dragging.current) return;
855
+ // Put back as it was
856
+ dragging.current.moved = false;
857
+ stop(width);
858
+ }}
859
+ onDoubleClick={() => onResize(PANEL_WIDTH)}
860
+ onKeyDown={(event) => {
861
+ const step = event.shiftKey ? 64 : 16;
862
+ if (event.key === 'ArrowLeft') onResize(clampPanelWidth(width + step, viewportWidth()));
863
+ else if (event.key === 'ArrowRight') onResize(clampPanelWidth(width - step, viewportWidth()));
864
+ else return;
865
+ event.preventDefault();
866
+ }}
867
+ className="group absolute inset-y-0 left-0 z-10 hidden w-1.5 cursor-col-resize outline-hidden lg:block"
868
+ >
869
+ <span
870
+ aria-hidden="true"
871
+ className={`absolute inset-y-0 left-0 w-0.5 transition-colors ${
872
+ isDragging
873
+ ? 'bg-[rgb(var(--ec-accent))]'
874
+ : 'group-hover:bg-[rgb(var(--ec-accent)/0.6)] group-focus-visible:bg-[rgb(var(--ec-accent))]'
875
+ }`}
876
+ />
877
+ </div>
878
+ );
879
+ }
880
+ );
881
+ PanelResizeHandle.displayName = 'PanelResizeHandle';
882
+
796
883
  const markdownComponents = {
797
884
  a: ({ node: _node, ...props }: any) => {
798
885
  const nodeIds = nodesInFocusLink(props.href);
@@ -989,6 +1076,24 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
989
1076
  const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
990
1077
  const [pathname, setPathname] = useState('');
991
1078
  const [isFullscreen, setIsFullscreen] = useState(false);
1079
+ // How wide they made the panel: the default until the width they left it at is read, after hydrating (within the
1080
+ // panel's own limits: the window's are applied as it's shown, so it's back to that width when the window's wide again)
1081
+ const panelRef = useRef<HTMLDivElement | null>(null);
1082
+ const [panelWidth, setPanelWidth] = useState(PANEL_WIDTH);
1083
+ useEffect(() => setPanelWidth(readPanelWidth(Infinity)), []);
1084
+ // How wide it's shown: that, leaving room for the page in this window (checked again as the window's resized; it only
1085
+ // re-renders when this changes)
1086
+ const [shownWidth, setShownWidth] = useState(PANEL_WIDTH);
1087
+ useEffect(() => {
1088
+ const fit = () => setShownWidth(clampPanelWidth(panelWidth, viewportWidth()));
1089
+ fit();
1090
+ window.addEventListener('resize', fit);
1091
+ return () => window.removeEventListener('resize', fit);
1092
+ }, [panelWidth]);
1093
+ const resizePanel = useCallback((width: number) => {
1094
+ setPanelWidth(width);
1095
+ savePanelWidth(width);
1096
+ }, []);
992
1097
  const [tools, setTools] = useState<ToolMetadata[]>([]);
993
1098
  const [showScrollButton, setShowScrollButton] = useState(false);
994
1099
  const chatApiUrl = useMemo(() => buildUrl('/api/chat', true), []);
@@ -1186,9 +1291,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1186
1291
  // Looked up each time: the panel stays open across ClientRouter navigations (the header persists), but each one
1187
1292
  // swaps in a new page that needs pushing over too
1188
1293
  const getElements = () => ({
1189
- elements: [document.getElementById('eventcatalog-application'), document.getElementById('eventcatalog-header')].filter(
1190
- Boolean
1191
- ) as HTMLElement[],
1294
+ elements: pageBesidePanel(),
1192
1295
  docsSidebarEl: document.getElementById('eventcatalog-docs-sidebar'),
1193
1296
  });
1194
1297
 
@@ -1200,7 +1303,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1200
1303
  if (!el.style.transition) {
1201
1304
  el.style.transition = 'padding-right 420ms cubic-bezier(0.16, 1, 0.3, 1)';
1202
1305
  }
1203
- el.style.paddingRight = pushContent ? `${PANEL_WIDTH}px` : '0';
1306
+ el.style.paddingRight = pushContent ? `${shownWidth}px` : '0';
1204
1307
  });
1205
1308
  if (docsSidebarEl) docsSidebarEl.style.display = pushContent ? 'none' : '';
1206
1309
  };
@@ -1221,7 +1324,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1221
1324
  docsSidebarEl.style.display = '';
1222
1325
  }
1223
1326
  };
1224
- }, [isOpen, isFullscreen]);
1327
+ }, [isOpen, isFullscreen, shownWidth]);
1225
1328
 
1226
1329
  // Submit message handler
1227
1330
  const submitMessage = useCallback(
@@ -1342,12 +1445,13 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1342
1445
  {!isFullscreen && (
1343
1446
  <div
1344
1447
  ref={(element) => {
1448
+ panelRef.current = element;
1345
1449
  element?.toggleAttribute('inert', !isOpen);
1346
1450
  }}
1347
1451
  aria-hidden={!isOpen}
1348
1452
  className="ec-chat-surface fixed top-0 right-0 h-[100dvh] z-[200] border-l border-[rgb(var(--ec-page-border))] flex flex-col overflow-hidden"
1349
1453
  style={{
1350
- width: `min(${PANEL_WIDTH}px, 100vw)`,
1454
+ width: `min(${shownWidth}px, 100vw)`,
1351
1455
  transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
1352
1456
  transition: 'transform 420ms cubic-bezier(0.16, 1, 0.3, 1)',
1353
1457
  background: `
@@ -1356,6 +1460,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1356
1460
  `,
1357
1461
  }}
1358
1462
  >
1463
+ <PanelResizeHandle panel={panelRef} width={shownWidth} onResize={resizePanel} />
1359
1464
  {/* Header */}
1360
1465
  <div className="flex-none shrink-0 border-b border-[rgb(var(--ec-page-border))]">
1361
1466
  <div className="flex items-center justify-between px-4 py-3">
@@ -0,0 +1,28 @@
1
+ /** How wide the assistant's panel is: dragged wider (or back) by its left edge, and remembered in this browser */
2
+ export const PANEL_WIDTH = 400;
3
+ export const MIN_PANEL_WIDTH = 360;
4
+ export const MAX_PANEL_WIDTH = 800;
5
+ // How much of the page stays beside it, at least
6
+ const MIN_PAGE_WIDTH = 480;
7
+ const STORAGE_KEY = 'eventcatalog-chat-panel-width';
8
+
9
+ /** Within the panel's limits, leaving room for the page in a window this wide */
10
+ export const clampPanelWidth = (width: number, viewportWidth: number) =>
11
+ Math.round(Math.max(MIN_PANEL_WIDTH, Math.min(width, MAX_PANEL_WIDTH, viewportWidth - MIN_PAGE_WIDTH)));
12
+
13
+ /** The width they left it at, or the default */
14
+ export const readPanelWidth = (viewportWidth: number) => {
15
+ try {
16
+ const saved = Number(localStorage.getItem(STORAGE_KEY));
17
+ return saved ? clampPanelWidth(saved, viewportWidth) : PANEL_WIDTH;
18
+ } catch {
19
+ return PANEL_WIDTH;
20
+ }
21
+ };
22
+
23
+ export const savePanelWidth = (width: number) => {
24
+ try {
25
+ if (width === PANEL_WIDTH) localStorage.removeItem(STORAGE_KEY);
26
+ else localStorage.setItem(STORAGE_KEY, String(width));
27
+ } catch {}
28
+ };
@@ -4,7 +4,9 @@ const { title } = Astro.props;
4
4
 
5
5
  <li class="mb-8 ml-6 w-full xl:max-w-[90%] step">
6
6
  <div class="flex items-center mb-4">
7
- <span class="step-number absolute flex items-center justify-center w-6 h-6 bg-primary/80 rounded-md -left-3 text-white">
7
+ <span
8
+ class="step-number absolute flex items-center justify-center w-6 h-6 rounded-md -left-3 text-xs font-semibold bg-[rgb(var(--ec-accent-subtle))] text-[rgb(var(--ec-accent))] ring-4 ring-[rgb(var(--ec-page-bg))]"
9
+ >
8
10
  <div></div>
9
11
  </span>
10
12
  <h3 class="font-semibold text-lg ml-0">{title}</h3>
@@ -29,7 +31,7 @@ const { title } = Astro.props;
29
31
  color: rgb(var(--ec-page-text-muted));
30
32
  text-decoration: underline;
31
33
  &:hover {
32
- color: #b977f9;
34
+ color: rgb(var(--ec-accent));
33
35
  }
34
36
  }
35
37
  </style>
@@ -1,110 +1,9 @@
1
1
  import { ArrowsPointingOutIcon } from '@heroicons/react/24/outline';
2
2
  import type { VersionDiff } from './types';
3
3
  import { useDarkMode } from './useDarkMode';
4
+ import { getDiffDarkStyles } from './diff-dark-styles';
4
5
 
5
- // Dark mode overrides for diff2html - scoped under .diff-dark-mode
6
- const DIFF_DARK_STYLES = `
7
- .diff-dark-mode .d2h-wrapper {
8
- color: #e5e7eb;
9
- }
10
- .diff-dark-mode .d2h-file-header {
11
- background-color: rgba(255,255,255,0.05);
12
- border-bottom-color: rgba(255,255,255,0.1);
13
- }
14
- .diff-dark-mode .d2h-file-header .d2h-file-name {
15
- color: #e5e7eb;
16
- }
17
- .diff-dark-mode .d2h-diff-table {
18
- border-color: rgba(255,255,255,0.1);
19
- }
20
- .diff-dark-mode .d2h-code-side-linenumber,
21
- .diff-dark-mode .d2h-code-linenumber {
22
- background-color: rgba(255,255,255,0.03);
23
- border-color: rgba(255,255,255,0.08);
24
- color: #6b7280;
25
- }
26
- .diff-dark-mode .d2h-code-line,
27
- .diff-dark-mode .d2h-code-side-line {
28
- background-color: transparent;
29
- border-color: rgba(255,255,255,0.06);
30
- color: #d1d5db;
31
- }
32
- .diff-dark-mode .d2h-code-line-ctn {
33
- color: #d1d5db;
34
- }
35
- /* Deletion lines */
36
- .diff-dark-mode .d2h-del {
37
- background-color: rgba(239,68,68,0.1);
38
- border-color: rgba(239,68,68,0.15);
39
- }
40
- .diff-dark-mode .d2h-del .d2h-code-side-linenumber,
41
- .diff-dark-mode .d2h-del .d2h-code-linenumber {
42
- background-color: rgba(239,68,68,0.15);
43
- border-color: rgba(239,68,68,0.15);
44
- color: #f87171;
45
- }
46
- .diff-dark-mode .d2h-del .d2h-code-line-ctn {
47
- color: #fca5a5;
48
- }
49
- .diff-dark-mode del {
50
- background-color: rgba(239,68,68,0.25);
51
- color: #fca5a5;
52
- text-decoration: none;
53
- }
54
- /* Addition lines */
55
- .diff-dark-mode .d2h-ins {
56
- background-color: rgba(34,197,94,0.1);
57
- border-color: rgba(34,197,94,0.15);
58
- }
59
- .diff-dark-mode .d2h-ins .d2h-code-side-linenumber,
60
- .diff-dark-mode .d2h-ins .d2h-code-linenumber {
61
- background-color: rgba(34,197,94,0.15);
62
- border-color: rgba(34,197,94,0.15);
63
- color: #4ade80;
64
- }
65
- .diff-dark-mode .d2h-ins .d2h-code-line-ctn {
66
- color: #bbf7d0;
67
- }
68
- .diff-dark-mode ins {
69
- background-color: rgba(34,197,94,0.25);
70
- color: #bbf7d0;
71
- text-decoration: none;
72
- }
73
- /* Info/context header */
74
- .diff-dark-mode .d2h-info {
75
- background-color: rgba(59,130,246,0.08);
76
- border-color: rgba(59,130,246,0.15);
77
- color: #93c5fd;
78
- }
79
- /* File diff border */
80
- .diff-dark-mode .d2h-file-diff {
81
- border-color: rgba(255,255,255,0.1);
82
- }
83
- .diff-dark-mode .d2h-file-side-diff {
84
- border-color: rgba(255,255,255,0.1);
85
- }
86
- /* Tag styles */
87
- .diff-dark-mode .d2h-tag {
88
- background-color: rgba(59,130,246,0.15);
89
- border-color: rgba(59,130,246,0.3);
90
- color: #93c5fd;
91
- }
92
- /* Empty placeholder lines */
93
- .diff-dark-mode .d2h-code-side-emptyplaceholder,
94
- .diff-dark-mode .d2h-emptyplaceholder {
95
- background-color: rgba(255,255,255,0.02);
96
- border-color: rgba(255,255,255,0.06);
97
- }
98
- /* File wrapper border */
99
- .diff-dark-mode .d2h-file-wrapper {
100
- border-color: rgba(255,255,255,0.1);
101
- border-radius: 0.5rem;
102
- overflow: hidden;
103
- }
104
- .diff-dark-mode .d2h-files-diff {
105
- border-color: rgba(255,255,255,0.1);
106
- }
107
- `;
6
+ const DIFF_DARK_STYLES = getDiffDarkStyles('.diff-dark-mode');
108
7
 
109
8
  interface DiffViewerProps {
110
9
  diffs: VersionDiff[];
@@ -0,0 +1,104 @@
1
+ // Dark mode overrides for diff2html, scoped under the given selector.
2
+ // Shared by the Schema Explorer diff viewer and the changelog page.
3
+ export const getDiffDarkStyles = (scope: string) => `
4
+ ${scope} .d2h-wrapper {
5
+ color: #e5e7eb;
6
+ }
7
+ ${scope} .d2h-file-header {
8
+ background-color: rgba(255,255,255,0.05);
9
+ border-bottom-color: rgba(255,255,255,0.1);
10
+ }
11
+ ${scope} .d2h-file-header .d2h-file-name {
12
+ color: #e5e7eb;
13
+ }
14
+ ${scope} .d2h-diff-table {
15
+ border-color: rgba(255,255,255,0.1);
16
+ }
17
+ ${scope} .d2h-code-side-linenumber,
18
+ ${scope} .d2h-code-linenumber {
19
+ background-color: rgba(255,255,255,0.03);
20
+ border-color: rgba(255,255,255,0.08);
21
+ color: #6b7280;
22
+ }
23
+ ${scope} .d2h-code-line,
24
+ ${scope} .d2h-code-side-line {
25
+ background-color: transparent;
26
+ border-color: rgba(255,255,255,0.06);
27
+ color: #d1d5db;
28
+ }
29
+ ${scope} .d2h-code-line-ctn {
30
+ color: #d1d5db;
31
+ }
32
+ /* Deletion lines */
33
+ ${scope} .d2h-del {
34
+ background-color: rgba(239,68,68,0.1);
35
+ border-color: rgba(239,68,68,0.15);
36
+ }
37
+ ${scope} .d2h-del .d2h-code-side-linenumber,
38
+ ${scope} .d2h-del .d2h-code-linenumber {
39
+ background-color: rgba(239,68,68,0.15);
40
+ border-color: rgba(239,68,68,0.15);
41
+ color: #f87171;
42
+ }
43
+ ${scope} .d2h-del .d2h-code-line-ctn {
44
+ color: #fca5a5;
45
+ }
46
+ ${scope} del {
47
+ background-color: rgba(239,68,68,0.25);
48
+ color: #fca5a5;
49
+ text-decoration: none;
50
+ }
51
+ /* Addition lines */
52
+ ${scope} .d2h-ins {
53
+ background-color: rgba(34,197,94,0.1);
54
+ border-color: rgba(34,197,94,0.15);
55
+ }
56
+ ${scope} .d2h-ins .d2h-code-side-linenumber,
57
+ ${scope} .d2h-ins .d2h-code-linenumber {
58
+ background-color: rgba(34,197,94,0.15);
59
+ border-color: rgba(34,197,94,0.15);
60
+ color: #4ade80;
61
+ }
62
+ ${scope} .d2h-ins .d2h-code-line-ctn {
63
+ color: #bbf7d0;
64
+ }
65
+ ${scope} ins {
66
+ background-color: rgba(34,197,94,0.25);
67
+ color: #bbf7d0;
68
+ text-decoration: none;
69
+ }
70
+ /* Info/context header */
71
+ ${scope} .d2h-info {
72
+ background-color: rgba(59,130,246,0.08);
73
+ border-color: rgba(59,130,246,0.15);
74
+ color: #93c5fd;
75
+ }
76
+ /* File diff border */
77
+ ${scope} .d2h-file-diff {
78
+ border-color: rgba(255,255,255,0.1);
79
+ }
80
+ ${scope} .d2h-file-side-diff {
81
+ border-color: rgba(255,255,255,0.1);
82
+ }
83
+ /* Tag styles */
84
+ ${scope} .d2h-tag {
85
+ background-color: rgba(59,130,246,0.15);
86
+ border-color: rgba(59,130,246,0.3);
87
+ color: #93c5fd;
88
+ }
89
+ /* Empty placeholder lines */
90
+ ${scope} .d2h-code-side-emptyplaceholder,
91
+ ${scope} .d2h-emptyplaceholder {
92
+ background-color: rgba(255,255,255,0.02);
93
+ border-color: rgba(255,255,255,0.06);
94
+ }
95
+ /* File wrapper border */
96
+ ${scope} .d2h-file-wrapper {
97
+ border-color: rgba(255,255,255,0.1);
98
+ border-radius: 0.5rem;
99
+ overflow: hidden;
100
+ }
101
+ ${scope} .d2h-files-diff {
102
+ border-color: rgba(255,255,255,0.1);
103
+ }
104
+ `;