@eventcatalog/core 3.29.2 → 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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-36IA4UE4.js → chunk-7IGMIOQF.js} +1 -1
- package/dist/{chunk-EGQGCB2B.js → chunk-HVOLSUC2.js} +1 -1
- package/dist/{chunk-DB4IQ3GB.js → chunk-LWVHWR77.js} +1 -1
- package/dist/{chunk-VEUNSJ6Z.js → chunk-QIJOBQZ7.js} +1 -1
- package/dist/{chunk-MEJOYC5Z.js → chunk-UY5QDWK7.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +11 -7
- package/eventcatalog/public/logo.png +0 -0
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +29 -24
- package/eventcatalog/src/components/EnvironmentDropdown.tsx +33 -21
- package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +3 -53
- package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +144 -91
- package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +112 -109
- package/eventcatalog/src/components/Header.astro +9 -19
- package/eventcatalog/src/components/MDX/Accordion/Accordion.tsx +12 -14
- package/eventcatalog/src/components/MDX/Accordion/AccordionGroup.astro +11 -3
- package/eventcatalog/src/components/MDX/Design/Design.astro +1 -1
- package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +15 -5
- package/eventcatalog/src/components/MDX/Tiles/Tile.astro +11 -8
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +164 -53
- package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +1 -1
- package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +4 -4
- package/eventcatalog/src/components/SchemaExplorer/Pagination.tsx +12 -10
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +48 -77
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +238 -169
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +189 -230
- package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +39 -36
- package/eventcatalog/src/components/Search/Search.astro +1 -1
- package/eventcatalog/src/components/Seo.astro +1 -1
- package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +218 -0
- package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +265 -0
- package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +371 -0
- package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +183 -0
- package/eventcatalog/src/components/Settings/LogoUpload.tsx +137 -0
- package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +91 -0
- package/eventcatalog/src/components/Settings/ReadOnlyBanner.tsx +18 -0
- package/eventcatalog/src/components/Settings/Row.tsx +59 -0
- package/eventcatalog/src/components/Settings/SettingsShared.tsx +176 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +3 -3
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +233 -261
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +116 -68
- package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +2 -2
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +130 -197
- package/eventcatalog/src/components/Tables/Table.tsx +21 -18
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +79 -131
- package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +104 -175
- package/eventcatalog/src/content.config.ts +1 -1
- package/eventcatalog/src/enterprise/auth/error.astro +1 -1
- package/eventcatalog/src/enterprise/auth/login.astro +1 -1
- package/eventcatalog/src/enterprise/auth/middleware/middleware-auth.ts +11 -7
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +97 -95
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +232 -181
- package/eventcatalog/src/enterprise/feature.ts +2 -1
- package/eventcatalog/src/enterprise/fields/pages/fields.astro +10 -8
- package/eventcatalog/src/enterprise/integrations/eventcatalog-features.ts +0 -8
- package/eventcatalog/src/layouts/DirectoryLayout.astro +17 -88
- package/eventcatalog/src/layouts/SettingsLayout.astro +116 -0
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +562 -141
- package/eventcatalog/src/layouts/VisualiserLayout.astro +7 -2
- package/eventcatalog/src/pages/_index.astro +253 -256
- package/eventcatalog/src/pages/api/settings/ai.ts +57 -0
- package/eventcatalog/src/pages/api/settings/general.ts +71 -0
- package/eventcatalog/src/pages/api/settings/logo.ts +113 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -3
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +223 -73
- package/eventcatalog/src/pages/discover/[type]/index.astro +22 -141
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +130 -30
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +147 -53
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +6 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +2 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +22 -19
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +71 -61
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +5 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +3 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +6 -32
- package/eventcatalog/src/pages/docs/llm/llms.txt.ts +5 -1
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +11 -4
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +12 -5
- package/eventcatalog/src/pages/schemas/explorer/index.astro +10 -8
- package/eventcatalog/src/pages/settings/assistant.astro +37 -0
- package/eventcatalog/src/pages/settings/billing.astro +17 -0
- package/eventcatalog/src/pages/settings/general.astro +32 -0
- package/eventcatalog/src/pages/settings/index.astro +21 -0
- package/eventcatalog/src/pages/settings/llm-access.astro +34 -0
- package/eventcatalog/src/pages/settings/mcp.astro +14 -0
- package/eventcatalog/src/pages/studio.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +2 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +2 -2
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +2 -7
- package/eventcatalog/src/styles/theme.css +95 -30
- package/eventcatalog/src/styles/themes/forest.css +17 -9
- package/eventcatalog/src/styles/themes/ocean.css +10 -2
- package/eventcatalog/src/styles/themes/sapphire.css +10 -2
- package/eventcatalog/src/styles/themes/sunset.css +25 -17
- package/eventcatalog/src/types/react-syntax-highlighter.d.ts +13 -0
- package/eventcatalog/src/utils/eventcatalog-config/config-schema.ts +49 -0
- package/eventcatalog/src/utils/eventcatalog-config/config-writer.ts +149 -0
- package/eventcatalog/src/utils/url-builder.ts +4 -2
- package/package.json +7 -5
- package/eventcatalog/public/logo.svg +0 -14
- package/eventcatalog/src/enterprise/plans/index.astro +0 -319
- package/eventcatalog/src/pages/docs/llm/llms-services.txt.ts +0 -81
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ExternalLink, Server, ServerCog } from 'lucide-react';
|
|
2
|
+
import { Row } from './Row';
|
|
3
|
+
import { LiveCard, MCP_DOCS_URL, UpgradeRequired, UrlPanel } from './SettingsShared';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
hasScalePlan: boolean;
|
|
7
|
+
inSSR: boolean;
|
|
8
|
+
mcpUrl: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const McpSettingsForm = ({ hasScalePlan, inSSR, mcpUrl }: Props) => {
|
|
12
|
+
const mcpAvailable = hasScalePlan && inSSR;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="divide-y divide-[rgb(var(--ec-page-border))]">
|
|
16
|
+
<Row
|
|
17
|
+
title="MCP Server"
|
|
18
|
+
description="Expose your catalog over the Model Context Protocol so AI agents (Claude Desktop, Cursor, etc.) can query your architecture as a live data source."
|
|
19
|
+
canEdit={false}
|
|
20
|
+
dirty={false}
|
|
21
|
+
>
|
|
22
|
+
{mcpAvailable ? (
|
|
23
|
+
<McpAvailable url={mcpUrl} />
|
|
24
|
+
) : !hasScalePlan ? (
|
|
25
|
+
<UpgradeRequired
|
|
26
|
+
tier="Scale"
|
|
27
|
+
blurb="The MCP Server is a Scale-plan feature. Upgrade to expose your catalog to AI agents over the Model Context Protocol."
|
|
28
|
+
docsUrl={MCP_DOCS_URL}
|
|
29
|
+
/>
|
|
30
|
+
) : (
|
|
31
|
+
<McpNeedsSSR />
|
|
32
|
+
)}
|
|
33
|
+
</Row>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const McpAvailable = ({ url }: { url: string }) => (
|
|
39
|
+
<div className="space-y-3">
|
|
40
|
+
<LiveCard
|
|
41
|
+
icon={<Server className="h-4 w-4" aria-hidden />}
|
|
42
|
+
title="MCP server is live"
|
|
43
|
+
description="Point Claude Desktop, Cursor, or any MCP-aware client at the endpoint below."
|
|
44
|
+
/>
|
|
45
|
+
<div className="rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg)/0.4)] px-4 py-3">
|
|
46
|
+
<p className="text-[12px] font-medium text-[rgb(var(--ec-page-text))]">Endpoint</p>
|
|
47
|
+
<UrlPanel url={url} />
|
|
48
|
+
<a
|
|
49
|
+
href={MCP_DOCS_URL}
|
|
50
|
+
target="_blank"
|
|
51
|
+
rel="noreferrer"
|
|
52
|
+
className="mt-3 inline-flex items-center gap-1 text-[12px] font-medium text-[rgb(var(--ec-accent))] hover:underline"
|
|
53
|
+
>
|
|
54
|
+
Connect a client
|
|
55
|
+
<ExternalLink className="h-3 w-3" aria-hidden />
|
|
56
|
+
</a>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const McpNeedsSSR = () => (
|
|
62
|
+
<div className="overflow-hidden rounded-lg border border-[rgb(var(--ec-accent)/0.4)] bg-gradient-to-br from-[rgb(var(--ec-accent)/0.1)] via-[rgb(var(--ec-accent)/0.05)] to-transparent">
|
|
63
|
+
<div className="flex items-start gap-3 px-4 py-3.5">
|
|
64
|
+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-[rgb(var(--ec-accent)/0.4)] bg-[rgb(var(--ec-accent)/0.1)] text-[rgb(var(--ec-accent))]">
|
|
65
|
+
<ServerCog className="h-4 w-4" aria-hidden />
|
|
66
|
+
</span>
|
|
67
|
+
<div className="flex-1 min-w-0">
|
|
68
|
+
<div className="flex items-center gap-2">
|
|
69
|
+
<p className="text-[13px] font-semibold text-[rgb(var(--ec-page-text))]">Server output mode required</p>
|
|
70
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-[rgb(var(--ec-accent)/0.4)] bg-[rgb(var(--ec-accent)/0.1)] px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-accent))]">
|
|
71
|
+
SSR
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
<p className="mt-1 text-[12px] leading-snug text-[rgb(var(--ec-page-text-muted))]">
|
|
75
|
+
The MCP Server requires your catalog to run in server (SSR) mode. Follow the setup guide to switch.
|
|
76
|
+
</p>
|
|
77
|
+
<div className="mt-3 flex flex-wrap items-center gap-3">
|
|
78
|
+
<a
|
|
79
|
+
href={MCP_DOCS_URL}
|
|
80
|
+
target="_blank"
|
|
81
|
+
rel="noreferrer"
|
|
82
|
+
className="inline-flex items-center gap-1 rounded-md bg-[rgb(var(--ec-accent))] px-3 py-1.5 text-[12px] font-semibold text-white shadow-sm transition-colors hover:bg-[rgb(var(--ec-accent-hover))]"
|
|
83
|
+
>
|
|
84
|
+
MCP setup guide
|
|
85
|
+
<ExternalLink className="h-3 w-3" aria-hidden />
|
|
86
|
+
</a>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Lock } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
export const ReadOnlyBanner = () => (
|
|
4
|
+
<div
|
|
5
|
+
role="status"
|
|
6
|
+
className="mb-6 flex items-start gap-3 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] p-4 text-sm text-[rgb(var(--ec-page-text))]"
|
|
7
|
+
>
|
|
8
|
+
<Lock className="mt-0.5 h-4 w-4 flex-shrink-0 text-[rgb(var(--ec-page-text-muted))]" aria-hidden />
|
|
9
|
+
<div className="space-y-1">
|
|
10
|
+
<p className="font-medium">Read-only</p>
|
|
11
|
+
<p className="text-[rgb(var(--ec-page-text-muted))]">
|
|
12
|
+
To edit these settings, run EventCatalog locally or update them in your{' '}
|
|
13
|
+
<code className="rounded bg-[rgb(var(--ec-page-bg)/0.78)] px-1 py-0.5 font-mono text-xs">eventcatalog.config.js</code>{' '}
|
|
14
|
+
file.
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AlertCircle } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
export const cn = (...parts: Array<string | false | undefined | null>): string => parts.filter(Boolean).join(' ');
|
|
4
|
+
|
|
5
|
+
export const inputBase =
|
|
6
|
+
'block w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-input-bg,var(--ec-page-bg)))] px-3 py-2 text-[13px] text-[rgb(var(--ec-page-text))] placeholder:text-[rgb(var(--ec-page-text-muted)/0.7)] transition-colors focus:border-[rgb(var(--ec-accent)/0.6)] focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ec-accent)/0.25)] disabled:cursor-not-allowed disabled:opacity-60';
|
|
7
|
+
|
|
8
|
+
export const monoInput = 'font-mono text-[12.5px] tracking-tight';
|
|
9
|
+
|
|
10
|
+
export const inputError = 'border-red-500/70 focus:border-red-500 focus:ring-red-500/20';
|
|
11
|
+
|
|
12
|
+
interface RowProps {
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
canEdit: boolean;
|
|
16
|
+
dirty: boolean;
|
|
17
|
+
saving?: boolean;
|
|
18
|
+
onSave?: () => void;
|
|
19
|
+
error?: string;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Row = ({ title, description, canEdit, dirty, saving, onSave, error, children }: RowProps) => (
|
|
24
|
+
<section className="grid grid-cols-1 gap-6 py-8 md:grid-cols-[minmax(0,_18rem)_minmax(0,_1fr)] md:gap-12">
|
|
25
|
+
<header className="space-y-1.5">
|
|
26
|
+
<h3 className="text-[14px] font-semibold tracking-tight text-[rgb(var(--ec-page-text))]">{title}</h3>
|
|
27
|
+
<p className="text-[13px] leading-relaxed text-[rgb(var(--ec-content-text-muted,var(--ec-page-text-muted)))]">
|
|
28
|
+
{description}
|
|
29
|
+
</p>
|
|
30
|
+
</header>
|
|
31
|
+
<div className="space-y-2.5">
|
|
32
|
+
{children}
|
|
33
|
+
{error && (
|
|
34
|
+
<p className="flex items-center gap-1.5 text-[12px] text-red-500">
|
|
35
|
+
<AlertCircle className="h-3 w-3 flex-shrink-0" aria-hidden />
|
|
36
|
+
{error}
|
|
37
|
+
</p>
|
|
38
|
+
)}
|
|
39
|
+
{onSave && canEdit && (
|
|
40
|
+
<div className="pt-1">
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
onClick={onSave}
|
|
44
|
+
disabled={!dirty || saving}
|
|
45
|
+
className={cn(
|
|
46
|
+
'inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-[12px] font-medium transition-colors',
|
|
47
|
+
dirty && !saving
|
|
48
|
+
? 'border-[rgb(var(--ec-accent)/0.5)] bg-[rgb(var(--ec-accent-subtle))] text-[rgb(var(--ec-accent-text))] hover:bg-[rgb(var(--ec-accent-subtle)/0.8)]'
|
|
49
|
+
: 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))]',
|
|
50
|
+
'disabled:cursor-not-allowed disabled:opacity-60'
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
{saving ? 'Saving…' : 'Save changes'}
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
);
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { toast } from 'sonner';
|
|
3
|
+
import { ExternalLink, Lock, Sparkles, Copy, Check as CheckIcon } from 'lucide-react';
|
|
4
|
+
import { cn } from './Row';
|
|
5
|
+
|
|
6
|
+
export const ASSISTANT_DOCS_URL =
|
|
7
|
+
'https://www.eventcatalog.dev/docs/development/ask-your-architecture/eventcatalog-assistant/what-is-eventcatalog-assistant';
|
|
8
|
+
export const ASSISTANT_CONFIGURATION_DOCS_URL =
|
|
9
|
+
'https://www.eventcatalog.dev/docs/development/ask-your-architecture/eventcatalog-assistant/configuration';
|
|
10
|
+
export const MCP_DOCS_URL = 'https://www.eventcatalog.dev/docs/development/ask-your-architecture/mcp-server/getting-started';
|
|
11
|
+
export const PRICING_URL = 'https://www.eventcatalog.dev/pricing';
|
|
12
|
+
|
|
13
|
+
interface UpgradeRequiredProps {
|
|
14
|
+
tier: string;
|
|
15
|
+
blurb: string;
|
|
16
|
+
docsUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const UpgradeRequired = ({ tier, blurb, docsUrl }: UpgradeRequiredProps) => (
|
|
20
|
+
<div className="overflow-hidden rounded-lg border border-amber-500/40 bg-gradient-to-br from-amber-500/10 via-amber-500/5 to-transparent">
|
|
21
|
+
<div className="flex items-start gap-3 px-4 py-3.5">
|
|
22
|
+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-amber-500/40 bg-amber-500/10 text-amber-500">
|
|
23
|
+
<Lock className="h-4 w-4" aria-hidden />
|
|
24
|
+
</span>
|
|
25
|
+
<div className="flex-1 min-w-0">
|
|
26
|
+
<div className="flex items-center gap-2">
|
|
27
|
+
<p className="text-[13px] font-semibold text-[rgb(var(--ec-page-text))]">Available on {tier}</p>
|
|
28
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-amber-500">
|
|
29
|
+
<Sparkles className="h-2.5 w-2.5" aria-hidden />
|
|
30
|
+
Upgrade
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
<p className="mt-1 text-[12px] leading-snug text-[rgb(var(--ec-page-text-muted))]">{blurb}</p>
|
|
34
|
+
<div className="mt-3 flex flex-wrap items-center gap-3">
|
|
35
|
+
<a
|
|
36
|
+
href={PRICING_URL}
|
|
37
|
+
target="_blank"
|
|
38
|
+
rel="noreferrer"
|
|
39
|
+
className="inline-flex items-center gap-1 rounded-md bg-amber-500 px-3 py-1.5 text-[12px] font-semibold text-white shadow-sm transition-colors hover:bg-amber-600"
|
|
40
|
+
>
|
|
41
|
+
View plans
|
|
42
|
+
<ExternalLink className="h-3 w-3" aria-hidden />
|
|
43
|
+
</a>
|
|
44
|
+
{docsUrl && (
|
|
45
|
+
<a
|
|
46
|
+
href={docsUrl}
|
|
47
|
+
target="_blank"
|
|
48
|
+
rel="noreferrer"
|
|
49
|
+
className="inline-flex items-center gap-1 text-[12px] font-medium text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]"
|
|
50
|
+
>
|
|
51
|
+
Learn more
|
|
52
|
+
<ExternalLink className="h-3 w-3" aria-hidden />
|
|
53
|
+
</a>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
interface UrlPanelProps {
|
|
62
|
+
url: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const UrlPanel = ({ url }: UrlPanelProps) => {
|
|
66
|
+
const [copied, setCopied] = useState(false);
|
|
67
|
+
const copy = async () => {
|
|
68
|
+
try {
|
|
69
|
+
await navigator.clipboard.writeText(new URL(url, window.location.origin).href);
|
|
70
|
+
setCopied(true);
|
|
71
|
+
setTimeout(() => setCopied(false), 1600);
|
|
72
|
+
} catch {
|
|
73
|
+
toast.error('Could not copy URL');
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
return (
|
|
77
|
+
<div className="mt-2 flex items-center gap-2">
|
|
78
|
+
<a
|
|
79
|
+
href={url}
|
|
80
|
+
target="_blank"
|
|
81
|
+
rel="noreferrer"
|
|
82
|
+
className="flex-1 truncate rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-1.5 font-mono text-[12px] text-[rgb(var(--ec-page-text))] transition-colors hover:border-[rgb(var(--ec-accent)/0.5)] hover:text-[rgb(var(--ec-accent))]"
|
|
83
|
+
>
|
|
84
|
+
{url}
|
|
85
|
+
</a>
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
onClick={copy}
|
|
89
|
+
aria-label="Copy URL"
|
|
90
|
+
className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))] transition-colors hover:bg-[rgb(var(--ec-page-bg)/0.78)] hover:text-[rgb(var(--ec-page-text))]"
|
|
91
|
+
>
|
|
92
|
+
{copied ? <CheckIcon className="h-3.5 w-3.5 text-green-500" aria-hidden /> : <Copy className="h-3.5 w-3.5" aria-hidden />}
|
|
93
|
+
</button>
|
|
94
|
+
<a
|
|
95
|
+
href={url}
|
|
96
|
+
target="_blank"
|
|
97
|
+
rel="noreferrer"
|
|
98
|
+
aria-label="Open in new tab"
|
|
99
|
+
className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))] transition-colors hover:bg-[rgb(var(--ec-page-bg)/0.78)] hover:text-[rgb(var(--ec-page-text))]"
|
|
100
|
+
>
|
|
101
|
+
<ExternalLink className="h-3.5 w-3.5" aria-hidden />
|
|
102
|
+
</a>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
interface LiveCardProps {
|
|
108
|
+
icon: React.ReactNode;
|
|
109
|
+
title: string;
|
|
110
|
+
description: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const LiveCard = ({ icon, title, description }: LiveCardProps) => (
|
|
114
|
+
<div className="flex items-center gap-3 rounded-lg border border-emerald-500/30 bg-emerald-500/5 px-4 py-3">
|
|
115
|
+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-emerald-500/30 bg-emerald-500/10 text-emerald-500">
|
|
116
|
+
{icon}
|
|
117
|
+
</span>
|
|
118
|
+
<div className="flex-1 min-w-0">
|
|
119
|
+
<p className="text-[13px] font-medium text-[rgb(var(--ec-page-text))]">{title}</p>
|
|
120
|
+
<p className="text-[12px] leading-snug text-[rgb(var(--ec-page-text-muted))]">{description}</p>
|
|
121
|
+
</div>
|
|
122
|
+
<span className="flex-shrink-0 rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-emerald-500">
|
|
123
|
+
Live
|
|
124
|
+
</span>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
interface ToggleProps {
|
|
129
|
+
checked: boolean;
|
|
130
|
+
disabled?: boolean;
|
|
131
|
+
onChange: (v: boolean) => void;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const Toggle = ({ checked, disabled, onChange }: ToggleProps) => (
|
|
135
|
+
<button
|
|
136
|
+
type="button"
|
|
137
|
+
role="switch"
|
|
138
|
+
aria-checked={checked}
|
|
139
|
+
disabled={disabled}
|
|
140
|
+
onClick={() => onChange(!checked)}
|
|
141
|
+
className={cn(
|
|
142
|
+
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors',
|
|
143
|
+
checked ? 'bg-[rgb(var(--ec-accent))]' : 'bg-[rgb(var(--ec-page-text-muted)/0.35)]',
|
|
144
|
+
disabled && 'cursor-not-allowed opacity-50'
|
|
145
|
+
)}
|
|
146
|
+
>
|
|
147
|
+
<span
|
|
148
|
+
className={cn(
|
|
149
|
+
'inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform',
|
|
150
|
+
checked ? 'translate-x-[1.125rem]' : 'translate-x-[0.1875rem]'
|
|
151
|
+
)}
|
|
152
|
+
/>
|
|
153
|
+
</button>
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
interface ToggleRowProps {
|
|
157
|
+
icon: React.ReactNode;
|
|
158
|
+
label: string;
|
|
159
|
+
hint: string;
|
|
160
|
+
checked: boolean;
|
|
161
|
+
disabled?: boolean;
|
|
162
|
+
onChange: (v: boolean) => void;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export const ToggleRow = ({ icon, label, hint, checked, disabled, onChange }: ToggleRowProps) => (
|
|
166
|
+
<div className="flex items-center gap-3 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-input-bg,var(--ec-page-bg)))] px-4 py-3">
|
|
167
|
+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))]">
|
|
168
|
+
{icon}
|
|
169
|
+
</span>
|
|
170
|
+
<div className="flex-1 min-w-0">
|
|
171
|
+
<p className="text-[13px] font-medium text-[rgb(var(--ec-page-text))]">{label}</p>
|
|
172
|
+
<p className="text-[12px] leading-snug text-[rgb(var(--ec-page-text-muted))]">{hint}</p>
|
|
173
|
+
</div>
|
|
174
|
+
<Toggle checked={checked} disabled={disabled} onChange={onChange} />
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
@@ -181,7 +181,7 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
|
|
|
181
181
|
return (
|
|
182
182
|
<>
|
|
183
183
|
{/* Search Input */}
|
|
184
|
-
<div className="px-
|
|
184
|
+
<div className="px-4 py-3 bg-[rgb(var(--ec-content-bg))] border-b border-[rgb(var(--ec-content-border))]">
|
|
185
185
|
<div className="flex gap-2">
|
|
186
186
|
<div className="relative flex-1">
|
|
187
187
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[rgb(var(--ec-input-placeholder))]" />
|
|
@@ -190,7 +190,7 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
|
|
|
190
190
|
placeholder="Search resources..."
|
|
191
191
|
value={searchQuery}
|
|
192
192
|
onChange={(e) => handleSearchChange(e.target.value)}
|
|
193
|
-
className="w-full pl-9! pr-8! py-2! text-sm! bg-[rgb(var(--ec-input-bg))]! border! border-[rgb(var(--ec-input-border))]! rounded-
|
|
193
|
+
className="w-full pl-9! pr-8! py-2.5! text-sm! bg-[rgb(var(--ec-input-bg))]! border! border-[rgb(var(--ec-input-border))]! rounded-xl! focus:outline-hidden! focus:ring-2! focus:ring-[rgb(var(--ec-accent))]! focus:border-transparent! text-[rgb(var(--ec-input-text))]! placeholder:text-[rgb(var(--ec-input-placeholder))]!"
|
|
194
194
|
/>
|
|
195
195
|
{searchQuery && (
|
|
196
196
|
<button
|
|
@@ -207,7 +207,7 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
|
|
|
207
207
|
<button
|
|
208
208
|
onClick={() => setShowFilterDropdown(!showFilterDropdown)}
|
|
209
209
|
className={cn(
|
|
210
|
-
'flex items-center justify-center w-10 h-10 rounded-
|
|
210
|
+
'flex items-center justify-center w-10 h-10 rounded-xl border transition-colors',
|
|
211
211
|
searchFilters.size > 0
|
|
212
212
|
? 'bg-[rgb(var(--ec-accent)/0.1)] border-[rgb(var(--ec-accent)/0.3)] text-[rgb(var(--ec-accent))]'
|
|
213
213
|
: 'bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-icon-hover))] hover:bg-[rgb(var(--ec-content-hover))]'
|