@farming-labs/next 0.2.104 → 0.2.106
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/api-reference.d.mts +41 -0
- package/dist/api-reference.mjs +755 -0
- package/dist/api.d.mts +30 -0
- package/dist/api.mjs +154 -0
- package/dist/changelog-rail-search.d.mts +46 -0
- package/dist/changelog-rail-search.mjs +443 -0
- package/dist/changelog.d.mts +36 -0
- package/dist/changelog.mjs +417 -0
- package/dist/client-callbacks.d.mts +9 -0
- package/dist/client-callbacks.mjs +62 -0
- package/dist/code-block-themes-CCE5ViGj.mjs +25 -0
- package/dist/config.d.mts +7 -0
- package/dist/config.mjs +2139 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6 -0
- package/dist/layout.d.mts +12 -0
- package/dist/layout.mjs +94 -0
- package/dist/mdx-plugins/rehype-code.d.mts +2 -0
- package/dist/mdx-plugins/rehype-code.mjs +3 -0
- package/dist/mdx-plugins/rehype-toc.d.mts +2 -0
- package/dist/mdx-plugins/rehype-toc.mjs +3 -0
- package/dist/mdx-plugins/remark-code-group.d.mts +2 -0
- package/dist/mdx-plugins/remark-code-group.mjs +3 -0
- package/dist/mdx-plugins/remark-heading.d.mts +6 -0
- package/dist/mdx-plugins/remark-heading.mjs +28 -0
- package/dist/mdx-plugins/remark-markdown-alternate.d.mts +21 -0
- package/dist/mdx-plugins/remark-markdown-alternate.mjs +78 -0
- package/dist/mdx-plugins/remark-og.d.mts +22 -0
- package/dist/mdx-plugins/remark-og.mjs +30 -0
- package/package.json +3 -3
package/dist/api.d.mts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createDocsAPI as createDocsAPI$1, createDocsMCPAPI as createDocsMCPAPI$1 } from "@farming-labs/theme/api";
|
|
2
|
+
import { DocsCloudRouteHandlerOptions, DocsCloudRouteHandlerOptions as DocsCloudRouteHandlerOptions$1, DocsCloudRouteHandlers, DocsCloudServer, DocsCloudServer as DocsCloudServer$1, createDocsCloudRouteHandler } from "@farming-labs/docs/cloud/server";
|
|
3
|
+
|
|
4
|
+
//#region src/api.d.ts
|
|
5
|
+
type DocsAPIOptions = NonNullable<Parameters<typeof createDocsAPI$1>[0]>;
|
|
6
|
+
type DocsMCPAPIOptions = NonNullable<Parameters<typeof createDocsMCPAPI$1>[0]>;
|
|
7
|
+
interface DocsAPICloudOptions extends DocsCloudRouteHandlerOptions$1 {
|
|
8
|
+
docsCloud?: DocsCloudServer$1;
|
|
9
|
+
}
|
|
10
|
+
type DocsAPICloudIntegration = DocsCloudServer$1 | DocsAPICloudOptions;
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the app project root for a Next route module.
|
|
13
|
+
*
|
|
14
|
+
* This handles source routes (`app/...` or `src/app/...`) and built production
|
|
15
|
+
* output (`.next/server/app/...` or custom-dist-dir `/server/app/...`).
|
|
16
|
+
*/
|
|
17
|
+
declare function resolveNextProjectRoot(metaUrl: string): string;
|
|
18
|
+
declare function createDocsAPI(options?: DocsAPIOptions, cloudIntegration?: DocsAPICloudIntegration): {
|
|
19
|
+
HEAD(request: Request): Promise<Response>;
|
|
20
|
+
GET(request: Request): Promise<Response>;
|
|
21
|
+
POST(request: Request): Promise<Response>;
|
|
22
|
+
};
|
|
23
|
+
declare function createDocsMCPAPI(options?: DocsMCPAPIOptions): {
|
|
24
|
+
GET(request: Request): Promise<Response>;
|
|
25
|
+
POST(request: Request): Promise<Response>;
|
|
26
|
+
DELETE(request: Request): Promise<Response>;
|
|
27
|
+
OPTIONS(request: Request): Promise<Response>;
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { DocsAPICloudIntegration, DocsAPICloudOptions, type DocsCloudRouteHandlerOptions, type DocsCloudRouteHandlers, type DocsCloudServer, createDocsAPI, createDocsCloudRouteHandler, createDocsMCPAPI, resolveNextProjectRoot };
|
package/dist/api.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
+
import { createDocsAPI as createDocsAPI$1, createDocsMCPAPI as createDocsMCPAPI$1 } from "@farming-labs/theme/api";
|
|
4
|
+
import { bundledAgentSkills } from "@farming-labs/docs/agent-skills-bundle";
|
|
5
|
+
import { createDocsCloudRouteHandler } from "@farming-labs/docs/cloud/server";
|
|
6
|
+
|
|
7
|
+
//#region src/api.ts
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the app project root for a Next route module.
|
|
10
|
+
*
|
|
11
|
+
* This handles source routes (`app/...` or `src/app/...`) and built production
|
|
12
|
+
* output (`.next/server/app/...` or custom-dist-dir `/server/app/...`).
|
|
13
|
+
*/
|
|
14
|
+
function resolveNextProjectRoot(metaUrl) {
|
|
15
|
+
const filePath = fileURLToPath(metaUrl);
|
|
16
|
+
let current = path.dirname(filePath);
|
|
17
|
+
while (true) {
|
|
18
|
+
const parent = path.dirname(current);
|
|
19
|
+
if (path.basename(current) === "app") {
|
|
20
|
+
if (path.basename(parent) === "src") return path.dirname(parent);
|
|
21
|
+
if (path.basename(parent) === "server") {
|
|
22
|
+
const serverParent = path.dirname(parent);
|
|
23
|
+
if (path.basename(serverParent) === "dev") return path.dirname(path.dirname(serverParent));
|
|
24
|
+
return path.dirname(serverParent);
|
|
25
|
+
}
|
|
26
|
+
return parent;
|
|
27
|
+
}
|
|
28
|
+
if (parent === current) return process.cwd();
|
|
29
|
+
current = parent;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function isNextRouteFile(filePath) {
|
|
33
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
34
|
+
return /\/(?:src\/)?app\/api\/.+\/route\.[cm]?[jt]sx?$/.test(normalized);
|
|
35
|
+
}
|
|
36
|
+
function inferNextProjectRootFromCaller() {
|
|
37
|
+
const previousPrepareStackTrace = Error.prepareStackTrace;
|
|
38
|
+
try {
|
|
39
|
+
Error.prepareStackTrace = (_error, stack) => stack;
|
|
40
|
+
const error = /* @__PURE__ */ new Error();
|
|
41
|
+
Error.captureStackTrace?.(error, inferNextProjectRootFromCaller);
|
|
42
|
+
const stack = error.stack;
|
|
43
|
+
for (const frame of stack ?? []) {
|
|
44
|
+
const fileName = frame.getFileName?.();
|
|
45
|
+
if (!fileName || !isNextRouteFile(fileName)) continue;
|
|
46
|
+
return resolveNextProjectRoot(pathToFileURL(fileName).href);
|
|
47
|
+
}
|
|
48
|
+
} catch {} finally {
|
|
49
|
+
Error.prepareStackTrace = previousPrepareStackTrace;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isRecord(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
function normalizeAction(value) {
|
|
56
|
+
return value?.trim().toLowerCase().replace(/_/g, "-") || void 0;
|
|
57
|
+
}
|
|
58
|
+
function isDocsCloudServer(value) {
|
|
59
|
+
return isRecord(value) && typeof value.handleRequest === "function";
|
|
60
|
+
}
|
|
61
|
+
function resolveDocsCloudIntegration(integration) {
|
|
62
|
+
if (!integration) return void 0;
|
|
63
|
+
if (isDocsCloudServer(integration)) return {
|
|
64
|
+
docsCloud: integration,
|
|
65
|
+
routeOptions: {}
|
|
66
|
+
};
|
|
67
|
+
if (!integration.docsCloud) return void 0;
|
|
68
|
+
return {
|
|
69
|
+
docsCloud: integration.docsCloud,
|
|
70
|
+
routeOptions: {
|
|
71
|
+
locale: integration.locale,
|
|
72
|
+
publicBaseUrl: integration.publicBaseUrl
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function isDocsCloudGetRequest(request) {
|
|
77
|
+
const url = new URL(request.url);
|
|
78
|
+
const cloud = normalizeAction(url.searchParams.get("cloud"));
|
|
79
|
+
const action = normalizeAction(url.searchParams.get("action"));
|
|
80
|
+
const format = normalizeAction(url.searchParams.get("format"));
|
|
81
|
+
return cloud === "config" || cloud === "public-config" || action === "cloud-config" || action === "docs-cloud-config" || format === "cloud-config" || format === "docs-cloud-config";
|
|
82
|
+
}
|
|
83
|
+
function isDocsCloudAction(action) {
|
|
84
|
+
return Boolean(action && [
|
|
85
|
+
"analytics",
|
|
86
|
+
"track",
|
|
87
|
+
"track-event",
|
|
88
|
+
"event",
|
|
89
|
+
"ask-ai",
|
|
90
|
+
"ai",
|
|
91
|
+
"chat",
|
|
92
|
+
"docs-cloud"
|
|
93
|
+
].includes(action));
|
|
94
|
+
}
|
|
95
|
+
async function readJson(request) {
|
|
96
|
+
try {
|
|
97
|
+
return await request.clone().json();
|
|
98
|
+
} catch {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function isDocsCloudPostRequest(request) {
|
|
103
|
+
const url = new URL(request.url);
|
|
104
|
+
const cloud = normalizeAction(url.searchParams.get("cloud"));
|
|
105
|
+
const action = normalizeAction(url.searchParams.get("action"));
|
|
106
|
+
if (isDocsCloudAction(cloud) || isDocsCloudAction(action)) return true;
|
|
107
|
+
const body = await readJson(request);
|
|
108
|
+
if (!isRecord(body)) return false;
|
|
109
|
+
if (isDocsCloudAction(normalizeAction(typeof body.action === "string" ? body.action : void 0))) return true;
|
|
110
|
+
if (typeof body.type === "string") return true;
|
|
111
|
+
if (isRecord(body.event) && typeof body.event.type === "string") return true;
|
|
112
|
+
if (isRecord(body.payload) && typeof body.payload.type === "string") return true;
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
function createDocsAPI(options = {}, cloudIntegration) {
|
|
116
|
+
const rootDir = options.rootDir ?? inferNextProjectRootFromCaller();
|
|
117
|
+
const handlers = createDocsAPI$1({
|
|
118
|
+
...options,
|
|
119
|
+
...rootDir ? { rootDir } : {},
|
|
120
|
+
_preloadedAgentSkills: options._preloadedAgentSkills ?? bundledAgentSkills
|
|
121
|
+
});
|
|
122
|
+
const integration = resolveDocsCloudIntegration(cloudIntegration);
|
|
123
|
+
if (!integration) return handlers;
|
|
124
|
+
return {
|
|
125
|
+
GET(request) {
|
|
126
|
+
if (isDocsCloudGetRequest(request)) return integration.docsCloud.handleRequest(request, integration.routeOptions);
|
|
127
|
+
return handlers.GET(request);
|
|
128
|
+
},
|
|
129
|
+
async HEAD(request) {
|
|
130
|
+
if (!isDocsCloudGetRequest(request)) return handlers.HEAD(request);
|
|
131
|
+
const response = await integration.docsCloud.handleRequest(request, integration.routeOptions);
|
|
132
|
+
return new Response(null, {
|
|
133
|
+
status: response.status,
|
|
134
|
+
statusText: response.statusText,
|
|
135
|
+
headers: response.headers
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
async POST(request) {
|
|
139
|
+
if (await isDocsCloudPostRequest(request)) return integration.docsCloud.handleRequest(request, integration.routeOptions);
|
|
140
|
+
return handlers.POST(request);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function createDocsMCPAPI(options = {}) {
|
|
145
|
+
const rootDir = options.rootDir ?? inferNextProjectRootFromCaller();
|
|
146
|
+
return createDocsMCPAPI$1({
|
|
147
|
+
...options,
|
|
148
|
+
...rootDir ? { rootDir } : {},
|
|
149
|
+
_preloadedAgentSkills: options._preloadedAgentSkills ?? bundledAgentSkills
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
export { createDocsAPI, createDocsCloudRouteHandler, createDocsMCPAPI, resolveNextProjectRoot };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/changelog-rail-search.d.ts
|
|
5
|
+
interface ChangelogDirectoryEntry {
|
|
6
|
+
slug: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
date: string;
|
|
10
|
+
url: string;
|
|
11
|
+
version?: string;
|
|
12
|
+
tags: string[];
|
|
13
|
+
authors: string[];
|
|
14
|
+
image?: string;
|
|
15
|
+
content?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
interface ChangelogDirectoryProps {
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
entries: ChangelogDirectoryEntry[];
|
|
21
|
+
searchEnabled: boolean;
|
|
22
|
+
actions?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
interface ChangelogTOCItem {
|
|
25
|
+
href: string;
|
|
26
|
+
title: string;
|
|
27
|
+
meta?: string;
|
|
28
|
+
}
|
|
29
|
+
declare function ChangelogTOC({
|
|
30
|
+
title,
|
|
31
|
+
items,
|
|
32
|
+
variant
|
|
33
|
+
}: {
|
|
34
|
+
title: string;
|
|
35
|
+
items: ChangelogTOCItem[];
|
|
36
|
+
variant?: "releases" | "content";
|
|
37
|
+
}): react_jsx_runtime0.JSX.Element | null;
|
|
38
|
+
declare function ChangelogDirectory({
|
|
39
|
+
title,
|
|
40
|
+
description,
|
|
41
|
+
entries,
|
|
42
|
+
searchEnabled,
|
|
43
|
+
actions
|
|
44
|
+
}: ChangelogDirectoryProps): react_jsx_runtime0.JSX.Element;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { ChangelogDirectory, ChangelogDirectoryEntry, ChangelogTOC };
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/changelog-rail-search.tsx
|
|
8
|
+
const MAGIC_PROSE = "fd-changelog-prose prose dark:prose-invert max-w-none min-w-0 prose-headings:scroll-mt-8 prose-headings:font-semibold prose-a:no-underline prose-headings:tracking-tight prose-headings:text-balance prose-p:tracking-tight prose-p:text-balance";
|
|
9
|
+
function formatTagLabel(tag) {
|
|
10
|
+
return tag.split(/[-_\s]+/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
|
|
11
|
+
}
|
|
12
|
+
function SearchIcon() {
|
|
13
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
14
|
+
"aria-hidden": "true",
|
|
15
|
+
viewBox: "0 0 24 24",
|
|
16
|
+
className: "size-4",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: "1.8",
|
|
20
|
+
strokeLinecap: "round",
|
|
21
|
+
strokeLinejoin: "round",
|
|
22
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
23
|
+
cx: "11",
|
|
24
|
+
cy: "11",
|
|
25
|
+
r: "7"
|
|
26
|
+
}), /* @__PURE__ */ jsx("path", { d: "m20 20-3.5-3.5" })]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function formatTimelineDate(value) {
|
|
30
|
+
const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
|
|
31
|
+
if (Number.isNaN(parsed.valueOf())) return value;
|
|
32
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
33
|
+
year: "numeric",
|
|
34
|
+
month: "long",
|
|
35
|
+
day: "numeric",
|
|
36
|
+
timeZone: "UTC"
|
|
37
|
+
}).format(parsed).toUpperCase();
|
|
38
|
+
}
|
|
39
|
+
function buildSearchHaystack(entry) {
|
|
40
|
+
return [
|
|
41
|
+
entry.title,
|
|
42
|
+
entry.description,
|
|
43
|
+
entry.date,
|
|
44
|
+
entry.version,
|
|
45
|
+
entry.tags.join(" "),
|
|
46
|
+
entry.authors.join(" ")
|
|
47
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
function EmptyResults({ query }) {
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
className: "rounded-lg border border-fd-border/70 bg-fd-muted/30 px-6 py-12 sm:px-8",
|
|
52
|
+
style: {
|
|
53
|
+
width: "min(100%, 48rem)",
|
|
54
|
+
maxWidth: "48rem",
|
|
55
|
+
minHeight: "10rem",
|
|
56
|
+
display: "flex",
|
|
57
|
+
flexDirection: "column",
|
|
58
|
+
alignItems: "flex-start",
|
|
59
|
+
justifyContent: "center",
|
|
60
|
+
textAlign: "left",
|
|
61
|
+
alignSelf: "flex-start",
|
|
62
|
+
marginLeft: 0,
|
|
63
|
+
marginRight: "auto"
|
|
64
|
+
},
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx("p", {
|
|
67
|
+
className: "text-xs font-medium uppercase tracking-[0.12em] text-fd-muted-foreground",
|
|
68
|
+
children: "No matches"
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ jsxs("h2", {
|
|
71
|
+
className: "mt-3 max-w-2xl text-2xl font-semibold tracking-tight text-fd-foreground sm:text-3xl",
|
|
72
|
+
children: [
|
|
73
|
+
"Nothing matched “",
|
|
74
|
+
query,
|
|
75
|
+
"”"
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx("p", {
|
|
79
|
+
className: "mt-3 max-w-xl text-sm leading-relaxed text-fd-muted-foreground",
|
|
80
|
+
children: "Try a release title, version, tag, or author name."
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function decodeHashValue(value) {
|
|
86
|
+
try {
|
|
87
|
+
return decodeURIComponent(value);
|
|
88
|
+
} catch {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getHashTargetElement(href) {
|
|
93
|
+
if (!href.startsWith("#")) return null;
|
|
94
|
+
const targetId = decodeHashValue(href.slice(1));
|
|
95
|
+
if (!targetId) return null;
|
|
96
|
+
const candidates = Array.from(document.querySelectorAll("[id]")).filter((candidate) => candidate.id === targetId);
|
|
97
|
+
const element = candidates.find((candidate) => {
|
|
98
|
+
const rect = candidate.getBoundingClientRect();
|
|
99
|
+
return rect.width > 0 || rect.height > 0;
|
|
100
|
+
}) ?? candidates[0];
|
|
101
|
+
if (!element) return null;
|
|
102
|
+
const rect = element.getBoundingClientRect();
|
|
103
|
+
if (rect.width > 0 || rect.height > 0) return element;
|
|
104
|
+
return element.closest("h1, h2, h3, h4, h5, h6, section, article") ?? element.parentElement;
|
|
105
|
+
}
|
|
106
|
+
function ChangelogTOC({ title, items, variant = "releases" }) {
|
|
107
|
+
const tocId = `fd-changelog-toc-${variant}-${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
108
|
+
const [activeHref, setActiveHref] = useState(items[0]?.href ?? "");
|
|
109
|
+
const activeSourceRef = useRef("hash");
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
let frameId = 0;
|
|
112
|
+
const updateActiveHrefFromScroll = () => {
|
|
113
|
+
const threshold = Math.max(140, window.innerHeight * .18);
|
|
114
|
+
let nextActiveHref = items[0]?.href ?? "";
|
|
115
|
+
for (const item of items) {
|
|
116
|
+
const element = getHashTargetElement(item.href);
|
|
117
|
+
if (!element) continue;
|
|
118
|
+
const { top } = element.getBoundingClientRect();
|
|
119
|
+
if (top <= threshold) nextActiveHref = item.href;
|
|
120
|
+
else break;
|
|
121
|
+
}
|
|
122
|
+
const scrollingElement = document.scrollingElement ?? document.documentElement;
|
|
123
|
+
if (scrollingElement.scrollTop > 0 && scrollingElement.scrollHeight - scrollingElement.scrollTop - scrollingElement.clientHeight <= 2) for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
124
|
+
const item = items[index];
|
|
125
|
+
if (item && getHashTargetElement(item.href)) {
|
|
126
|
+
nextActiveHref = item.href;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
setActiveHref(nextActiveHref);
|
|
131
|
+
};
|
|
132
|
+
const updateActiveHrefFromHash = () => {
|
|
133
|
+
if (!window.location.hash) return false;
|
|
134
|
+
const hashHref = `#${decodeHashValue(window.location.hash.slice(1))}`;
|
|
135
|
+
if (items.some((item) => item.href === hashHref)) {
|
|
136
|
+
setActiveHref(hashHref);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
};
|
|
141
|
+
const syncActiveHref = () => {
|
|
142
|
+
if (activeSourceRef.current === "hash" && updateActiveHrefFromHash()) return;
|
|
143
|
+
activeSourceRef.current = "scroll";
|
|
144
|
+
updateActiveHrefFromScroll();
|
|
145
|
+
};
|
|
146
|
+
const scheduleActiveHrefUpdate = () => {
|
|
147
|
+
if (frameId !== 0) return;
|
|
148
|
+
frameId = window.requestAnimationFrame(() => {
|
|
149
|
+
frameId = 0;
|
|
150
|
+
syncActiveHref();
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
const handleScroll = () => {
|
|
154
|
+
activeSourceRef.current = "scroll";
|
|
155
|
+
scheduleActiveHrefUpdate();
|
|
156
|
+
};
|
|
157
|
+
const handleHashChange = () => {
|
|
158
|
+
activeSourceRef.current = "hash";
|
|
159
|
+
if (updateActiveHrefFromHash()) return;
|
|
160
|
+
activeSourceRef.current = "scroll";
|
|
161
|
+
scheduleActiveHrefUpdate();
|
|
162
|
+
};
|
|
163
|
+
syncActiveHref();
|
|
164
|
+
const initialUpdateId = window.setTimeout(syncActiveHref, 0);
|
|
165
|
+
const settledUpdateId = window.setTimeout(syncActiveHref, 250);
|
|
166
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
167
|
+
window.addEventListener("resize", scheduleActiveHrefUpdate);
|
|
168
|
+
window.addEventListener("hashchange", handleHashChange);
|
|
169
|
+
return () => {
|
|
170
|
+
window.clearTimeout(initialUpdateId);
|
|
171
|
+
window.clearTimeout(settledUpdateId);
|
|
172
|
+
if (frameId !== 0) window.cancelAnimationFrame(frameId);
|
|
173
|
+
window.removeEventListener("scroll", handleScroll);
|
|
174
|
+
window.removeEventListener("resize", scheduleActiveHrefUpdate);
|
|
175
|
+
window.removeEventListener("hashchange", handleHashChange);
|
|
176
|
+
};
|
|
177
|
+
}, [items]);
|
|
178
|
+
if (items.length === 0) return null;
|
|
179
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
180
|
+
id: tocId,
|
|
181
|
+
className: "fd-changelog-toc",
|
|
182
|
+
"aria-label": title,
|
|
183
|
+
"data-fd-changelog-toc": "true",
|
|
184
|
+
"data-variant": variant,
|
|
185
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
186
|
+
className: "fd-changelog-toc-card",
|
|
187
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
188
|
+
className: "fd-changelog-toc-heading",
|
|
189
|
+
children: title
|
|
190
|
+
}), /* @__PURE__ */ jsx("nav", {
|
|
191
|
+
className: "fd-changelog-toc-list",
|
|
192
|
+
children: items.map((item) => {
|
|
193
|
+
const isActive = item.href === activeHref;
|
|
194
|
+
return /* @__PURE__ */ jsxs("a", {
|
|
195
|
+
href: item.href,
|
|
196
|
+
className: "fd-changelog-toc-link",
|
|
197
|
+
"data-fd-changelog-toc-link": "true",
|
|
198
|
+
"data-active": isActive ? "true" : "false",
|
|
199
|
+
"aria-current": isActive ? "location" : void 0,
|
|
200
|
+
onClick: () => setActiveHref(item.href),
|
|
201
|
+
children: [item.meta ? /* @__PURE__ */ jsx("span", {
|
|
202
|
+
className: "fd-changelog-toc-meta",
|
|
203
|
+
children: item.meta
|
|
204
|
+
}) : null, /* @__PURE__ */ jsx("span", {
|
|
205
|
+
className: "fd-changelog-toc-title",
|
|
206
|
+
children: item.title
|
|
207
|
+
})]
|
|
208
|
+
}, item.href);
|
|
209
|
+
})
|
|
210
|
+
})]
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function ChangelogTimelineItem({ entry, isLast }) {
|
|
215
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
216
|
+
id: entry.slug,
|
|
217
|
+
className: "fd-changelog-entry relative scroll-mt-24 not-prose isolate",
|
|
218
|
+
children: [
|
|
219
|
+
/* @__PURE__ */ jsxs("div", {
|
|
220
|
+
className: "fd-changelog-mobile-summary",
|
|
221
|
+
children: [entry.version ? /* @__PURE__ */ jsx("div", {
|
|
222
|
+
className: "fd-changelog-version-box",
|
|
223
|
+
children: entry.version
|
|
224
|
+
}) : /* @__PURE__ */ jsx("div", {}), /* @__PURE__ */ jsx("time", {
|
|
225
|
+
className: "fd-changelog-date",
|
|
226
|
+
style: { marginBottom: "10px" },
|
|
227
|
+
dateTime: entry.date,
|
|
228
|
+
children: formatTimelineDate(entry.date)
|
|
229
|
+
})]
|
|
230
|
+
}),
|
|
231
|
+
/* @__PURE__ */ jsxs("div", {
|
|
232
|
+
className: "fd-changelog-mobile-content",
|
|
233
|
+
style: isLast ? void 0 : { paddingBottom: "5rem" },
|
|
234
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
235
|
+
className: "flex flex-col gap-2",
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ jsx("h2", {
|
|
238
|
+
className: "m-0 text-balance text-lg font-semibold leading-snug tracking-tight text-fd-foreground md:text-xl",
|
|
239
|
+
children: /* @__PURE__ */ jsx(Link, {
|
|
240
|
+
href: entry.url,
|
|
241
|
+
className: "text-inherit no-underline hover:underline",
|
|
242
|
+
children: entry.title
|
|
243
|
+
})
|
|
244
|
+
}),
|
|
245
|
+
entry.tags.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
246
|
+
className: "flex flex-wrap gap-2",
|
|
247
|
+
children: entry.tags.map((tag) => /* @__PURE__ */ jsx("span", {
|
|
248
|
+
className: "fd-changelog-tag",
|
|
249
|
+
"data-testid": "changelog-tag",
|
|
250
|
+
children: formatTagLabel(tag)
|
|
251
|
+
}, `${entry.slug}-${tag}`))
|
|
252
|
+
}) : null,
|
|
253
|
+
entry.description ? /* @__PURE__ */ jsx("p", {
|
|
254
|
+
className: "m-0 max-w-2xl text-sm leading-relaxed text-fd-muted-foreground",
|
|
255
|
+
children: entry.description
|
|
256
|
+
}) : null
|
|
257
|
+
]
|
|
258
|
+
}), entry.content || entry.image ? /* @__PURE__ */ jsxs("div", {
|
|
259
|
+
className: MAGIC_PROSE,
|
|
260
|
+
children: [entry.image ? /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("img", {
|
|
261
|
+
src: entry.image,
|
|
262
|
+
alt: `${entry.title} preview`,
|
|
263
|
+
loading: "lazy",
|
|
264
|
+
decoding: "async"
|
|
265
|
+
}) }) : null, entry.content]
|
|
266
|
+
}) : null]
|
|
267
|
+
}),
|
|
268
|
+
/* @__PURE__ */ jsxs("div", {
|
|
269
|
+
className: "fd-changelog-desktop-grid",
|
|
270
|
+
style: isLast ? void 0 : { paddingBottom: "5rem" },
|
|
271
|
+
children: [
|
|
272
|
+
/* @__PURE__ */ jsx("div", {
|
|
273
|
+
className: "flex items-start justify-end pt-0.5",
|
|
274
|
+
children: entry.version ? /* @__PURE__ */ jsx("div", {
|
|
275
|
+
className: "fd-changelog-version-box",
|
|
276
|
+
children: entry.version
|
|
277
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
278
|
+
className: "h-9",
|
|
279
|
+
"aria-hidden": "true"
|
|
280
|
+
})
|
|
281
|
+
}),
|
|
282
|
+
/* @__PURE__ */ jsxs("div", {
|
|
283
|
+
className: "fd-changelog-rail",
|
|
284
|
+
"data-testid": "changelog-rail",
|
|
285
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
286
|
+
className: "fd-changelog-timeline-dot mt-1",
|
|
287
|
+
"data-testid": "changelog-timeline-dot",
|
|
288
|
+
"aria-hidden": true
|
|
289
|
+
}), isLast ? /* @__PURE__ */ jsx("div", {
|
|
290
|
+
className: "fd-changelog-rail-end-mask",
|
|
291
|
+
"aria-hidden": true
|
|
292
|
+
}) : null]
|
|
293
|
+
}),
|
|
294
|
+
/* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className: "min-w-0 space-y-5",
|
|
296
|
+
children: [/* @__PURE__ */ jsx("time", {
|
|
297
|
+
className: "fd-changelog-date block pt-0.5",
|
|
298
|
+
dateTime: entry.date,
|
|
299
|
+
children: formatTimelineDate(entry.date)
|
|
300
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
301
|
+
className: "space-y-6",
|
|
302
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
303
|
+
className: "flex flex-col gap-2",
|
|
304
|
+
children: [
|
|
305
|
+
/* @__PURE__ */ jsx("h2", {
|
|
306
|
+
className: "m-0 text-balance text-lg font-semibold leading-snug tracking-tight text-fd-foreground md:text-xl",
|
|
307
|
+
children: /* @__PURE__ */ jsx(Link, {
|
|
308
|
+
href: entry.url,
|
|
309
|
+
className: "text-inherit no-underline hover:underline",
|
|
310
|
+
children: entry.title
|
|
311
|
+
})
|
|
312
|
+
}),
|
|
313
|
+
entry.tags.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
314
|
+
className: "flex flex-wrap gap-2",
|
|
315
|
+
children: entry.tags.map((tag) => /* @__PURE__ */ jsx("span", {
|
|
316
|
+
className: "fd-changelog-tag",
|
|
317
|
+
"data-testid": "changelog-tag",
|
|
318
|
+
children: formatTagLabel(tag)
|
|
319
|
+
}, `${entry.slug}-${tag}`))
|
|
320
|
+
}) : null,
|
|
321
|
+
entry.description ? /* @__PURE__ */ jsx("p", {
|
|
322
|
+
className: "m-0 max-w-2xl text-sm leading-relaxed text-fd-muted-foreground",
|
|
323
|
+
children: entry.description
|
|
324
|
+
}) : null
|
|
325
|
+
]
|
|
326
|
+
}), entry.content || entry.image ? /* @__PURE__ */ jsxs("div", {
|
|
327
|
+
className: MAGIC_PROSE,
|
|
328
|
+
children: [entry.image ? /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("img", {
|
|
329
|
+
src: entry.image,
|
|
330
|
+
alt: `${entry.title} preview`,
|
|
331
|
+
loading: "lazy",
|
|
332
|
+
decoding: "async"
|
|
333
|
+
}) }) : null, entry.content]
|
|
334
|
+
}) : null]
|
|
335
|
+
})]
|
|
336
|
+
})
|
|
337
|
+
]
|
|
338
|
+
})
|
|
339
|
+
]
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function ChangelogDirectory({ title, description, entries, searchEnabled, actions }) {
|
|
343
|
+
const [query, setQuery] = useState("");
|
|
344
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
345
|
+
const filteredEntries = useMemo(() => {
|
|
346
|
+
if (!normalizedQuery) return entries;
|
|
347
|
+
return entries.filter((entry) => buildSearchHaystack(entry).includes(normalizedQuery));
|
|
348
|
+
}, [entries, normalizedQuery]);
|
|
349
|
+
const releaseCount = entries.length;
|
|
350
|
+
const hasResults = filteredEntries.length > 0;
|
|
351
|
+
const tocItems = filteredEntries.map((entry) => ({
|
|
352
|
+
href: `#${entry.slug}`,
|
|
353
|
+
title: entry.title,
|
|
354
|
+
meta: entry.version ?? formatTimelineDate(entry.date)
|
|
355
|
+
}));
|
|
356
|
+
const searchControl = searchEnabled ? /* @__PURE__ */ jsx("div", {
|
|
357
|
+
className: "fd-changelog-search-row",
|
|
358
|
+
children: /* @__PURE__ */ jsxs("label", {
|
|
359
|
+
className: "fd-changelog-search",
|
|
360
|
+
"aria-label": "Search changelog entries",
|
|
361
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
362
|
+
className: "fd-changelog-search-icon",
|
|
363
|
+
"aria-hidden": "true",
|
|
364
|
+
children: /* @__PURE__ */ jsx(SearchIcon, {})
|
|
365
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
366
|
+
type: "text",
|
|
367
|
+
inputMode: "search",
|
|
368
|
+
autoComplete: "off",
|
|
369
|
+
value: query,
|
|
370
|
+
onChange: (event) => setQuery(event.target.value),
|
|
371
|
+
placeholder: "Search changelog entries",
|
|
372
|
+
className: "fd-changelog-search-input"
|
|
373
|
+
})]
|
|
374
|
+
})
|
|
375
|
+
}) : null;
|
|
376
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
377
|
+
className: "fd-changelog-frame not-prose relative w-full pb-16",
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ jsx("div", {
|
|
380
|
+
className: "fd-changelog-header-strip border-b-0 border-fd-border/50",
|
|
381
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
382
|
+
className: "flex flex-wrap items-center justify-between gap-4",
|
|
383
|
+
style: {
|
|
384
|
+
paddingTop: "1.25rem",
|
|
385
|
+
paddingBottom: "1.25rem"
|
|
386
|
+
},
|
|
387
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
388
|
+
className: "min-w-0",
|
|
389
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
390
|
+
className: "text-2xl font-semibold tracking-tight text-fd-foreground md:text-3xl",
|
|
391
|
+
children: title
|
|
392
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
393
|
+
className: "mt-0.5 text-sm text-fd-muted-foreground",
|
|
394
|
+
children: [
|
|
395
|
+
releaseCount,
|
|
396
|
+
" ",
|
|
397
|
+
releaseCount === 1 ? "release" : "releases"
|
|
398
|
+
]
|
|
399
|
+
})]
|
|
400
|
+
}), actions ? /* @__PURE__ */ jsx("div", {
|
|
401
|
+
className: "flex flex-wrap items-center gap-2",
|
|
402
|
+
children: actions
|
|
403
|
+
}) : null]
|
|
404
|
+
})
|
|
405
|
+
}),
|
|
406
|
+
description || searchControl ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
407
|
+
description ? /* @__PURE__ */ jsx("p", {
|
|
408
|
+
className: "max-w-2xl text-base leading-relaxed text-fd-muted-foreground",
|
|
409
|
+
style: { marginTop: "1rem" },
|
|
410
|
+
children: description
|
|
411
|
+
}) : null,
|
|
412
|
+
searchControl ? /* @__PURE__ */ jsx("div", {
|
|
413
|
+
style: { marginTop: description ? "1rem" : "1.25rem" },
|
|
414
|
+
children: searchControl
|
|
415
|
+
}) : null,
|
|
416
|
+
/* @__PURE__ */ jsx("hr", {
|
|
417
|
+
className: "border-0 border-t border-fd-border/40",
|
|
418
|
+
style: { marginTop: "1rem" }
|
|
419
|
+
})
|
|
420
|
+
] }) : null,
|
|
421
|
+
/* @__PURE__ */ jsxs("div", {
|
|
422
|
+
className: hasResults ? "fd-changelog-shell fd-changelog-shell-shifted" : "fd-changelog-shell",
|
|
423
|
+
style: { paddingTop: "4rem" },
|
|
424
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
425
|
+
className: "fd-changelog-main fd-changelog-directory-feed relative",
|
|
426
|
+
children: hasResults ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
427
|
+
className: "fd-changelog-directory-line",
|
|
428
|
+
"aria-hidden": true
|
|
429
|
+
}), filteredEntries.map((entry, index) => /* @__PURE__ */ jsx(ChangelogTimelineItem, {
|
|
430
|
+
entry,
|
|
431
|
+
isLast: index === filteredEntries.length - 1
|
|
432
|
+
}, entry.slug))] }) : /* @__PURE__ */ jsx(EmptyResults, { query })
|
|
433
|
+
}), /* @__PURE__ */ jsx(ChangelogTOC, {
|
|
434
|
+
title: "Releases",
|
|
435
|
+
items: tocItems
|
|
436
|
+
})]
|
|
437
|
+
})
|
|
438
|
+
]
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
//#endregion
|
|
443
|
+
export { ChangelogDirectory, ChangelogTOC };
|