boltdocs 2.8.3 → 2.9.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.
Files changed (87) hide show
  1. package/bin/boltdocs.js +7 -6
  2. package/dist/{banner-MynZD_Ox.d.cts → banner-C_xkGxzI.d.cts} +1 -1
  3. package/dist/{banner-3N4Jd_L9.d.ts → banner-D2NddBfF.d.ts} +1 -1
  4. package/dist/cache-C2PiGyg8.cjs +6 -0
  5. package/dist/cache-DFW4R3S0.mjs +6 -0
  6. package/dist/chunk-Ds5LZdWN.cjs +6 -0
  7. package/dist/client/index.cjs +693 -488
  8. package/dist/client/index.d.cts +74 -8
  9. package/dist/client/index.d.ts +74 -8
  10. package/dist/client/index.js +692 -489
  11. package/dist/client/mdx.cjs +1 -1
  12. package/dist/client/mdx.js +1 -1
  13. package/dist/client/primitives.cjs +4 -4
  14. package/dist/client/primitives.d.cts +1 -1
  15. package/dist/client/primitives.d.ts +1 -1
  16. package/dist/client/primitives.js +4 -4
  17. package/dist/client/theme/neutral.css +5 -3
  18. package/dist/client/theme/reset.css +19 -0
  19. package/dist/{docs-layout-CwCq42Zt.cjs → docs-layout-3TpAt6MB.cjs} +302 -248
  20. package/dist/{docs-layout-Dn6S5g59.js → docs-layout-6FQ8__ok.js} +303 -249
  21. package/dist/doctor-BY1tSmQd.mjs +34 -0
  22. package/dist/{doctor-DyNUVe96.cjs → doctor-Bknon8f5.cjs} +1 -1
  23. package/dist/doctor-DcFLi4t1.cjs +34 -0
  24. package/dist/{doctor-aN_leTbh.mjs → doctor-wsPTzt8Y.mjs} +1 -1
  25. package/dist/{generator-CC2yHzhZ.cjs → generator-BEIF6MOx.cjs} +2 -2
  26. package/dist/{generator-BHCrLU6h.mjs → generator-DILs0EFN.mjs} +1 -1
  27. package/dist/handler-B31cxNw0.mjs +6 -0
  28. package/dist/handler-DfhH9D1b.mjs +28 -0
  29. package/dist/handler-Djy0HfsI.cjs +28 -0
  30. package/dist/{icons-dev-DvJ-hh9x.cjs → icons-dev-BryEFkJu.cjs} +96 -7
  31. package/dist/{icons-dev-Oju24Wjp.js → icons-dev-kJyGWNeg.js} +79 -8
  32. package/dist/{image-Ch4-GxdO.cjs → image-B9YA_oQ_.cjs} +24 -10
  33. package/dist/{image-Do8V9PCW.js → image-CjYu9Eml.js} +24 -10
  34. package/dist/{mdx-5oeCOFhH.js → mdx-Cy_c2zio.js} +116 -33
  35. package/dist/{mdx-BGM7LjW5.cjs → mdx-WXjAMS8Y.cjs} +121 -32
  36. package/dist/{meta-loader-Cv9O0Pzl.cjs → meta-loader-D0V6oOQt.cjs} +1 -1
  37. package/dist/node/cli-entry.cjs +3 -3
  38. package/dist/node/cli-entry.mjs +3 -3
  39. package/dist/node/index.cjs +1 -1
  40. package/dist/node/index.d.cts +368 -24
  41. package/dist/node/index.d.mts +369 -24
  42. package/dist/node/index.mjs +1 -1
  43. package/dist/node/routes/worker.cjs +1 -1
  44. package/dist/node/routes/worker.mjs +1 -1
  45. package/dist/node-DV-EPtMU.mjs +160 -0
  46. package/dist/node-vOVNRABe.cjs +160 -0
  47. package/dist/{package-CHxJV4Jy.mjs → package-BK_82QLX.mjs} +1 -1
  48. package/dist/{package-B_SoaGeu.cjs → package-OxKE0p6j.cjs} +1 -1
  49. package/dist/{parser-B7-6PyQz.cjs → parser-C2Pw18LY.cjs} +1 -1
  50. package/dist/{parser-BzB-zCkF.cjs → parser-DJoEF96Y.cjs} +1 -1
  51. package/dist/{parser-D0PVghVt.mjs → parser-DScG_PTs.mjs} +1 -1
  52. package/dist/routes--LYHSHT7.cjs +6 -0
  53. package/dist/routes-BAsfsn_e.mjs +6 -0
  54. package/dist/routes-C6Kr2HFN.cjs +6 -0
  55. package/dist/routes-CKgGAy8P.mjs +6 -0
  56. package/dist/{search-dialog-BXVoecTx.cjs → search-dialog-BhXg05Ri.cjs} +1 -1
  57. package/dist/{search-dialog-BYhOov4S.cjs → search-dialog-BsAiQgnx.cjs} +2 -2
  58. package/dist/{search-dialog-C09riYmx.js → search-dialog-CaOO1Q4i.js} +2 -2
  59. package/dist/{search-dialog-CUeAfy-8.cjs → search-dialog-CzwvKoLW.cjs} +1 -1
  60. package/dist/{search-dialog-DHc_8FFX.js → search-dialog-DRNJsxOv.js} +1 -1
  61. package/dist/{search-dialog-D8gLkhUV.js → search-dialog-DaR66wl0.js} +1 -1
  62. package/dist/shiki-adapter-CUtj-xKv.cjs +6 -0
  63. package/dist/shiki-adapter-EZptJAmW.mjs +6 -0
  64. package/dist/shiki-adapter-F-P-lDon.mjs +6 -0
  65. package/dist/shiki-adapter-PQBl32AN.cjs +6 -0
  66. package/dist/{sidebar-Dlkgbxs6.d.cts → sidebar-BtJyWHy4.d.cts} +43 -4
  67. package/dist/{sidebar-DNq4_ZAa.d.ts → sidebar-C4fuRYYS.d.ts} +43 -4
  68. package/dist/{utils-BYITg7T5.mjs → utils-DC4Wq-S2.mjs} +1 -1
  69. package/dist/{utils-Cjmx1hhk.cjs → utils-wHud9ny5.cjs} +1 -1
  70. package/dist/worker-pool-BS1LX67P.cjs +6 -0
  71. package/dist/worker-pool-DRv8ef4z.mjs +6 -0
  72. package/package.json +7 -3
  73. package/src/shared/types.ts +36 -3
  74. package/dist/cache-BMUyNiiA.mjs +0 -6
  75. package/dist/cache-CKm45d2w.cjs +0 -6
  76. package/dist/chunk-CU-zTemE.cjs +0 -6
  77. package/dist/doctor-BArviV8X.cjs +0 -28
  78. package/dist/doctor-CgLA7_Uv.mjs +0 -28
  79. package/dist/node-MsTvOgJN.mjs +0 -159
  80. package/dist/node-h9HmhAFB.cjs +0 -159
  81. package/dist/routes-BW6Dif_K.mjs +0 -6
  82. package/dist/routes-DJNJ-rTt.cjs +0 -6
  83. package/dist/routes-DiYC4nD2.cjs +0 -6
  84. package/dist/routes-ERSGuFQK.mjs +0 -6
  85. package/dist/worker-pool-CtqklOXq.cjs +0 -6
  86. package/dist/worker-pool-k0DY6k8T.mjs +0 -6
  87. /package/dist/{meta-loader-DzwDFtdT.mjs → meta-loader-By22EnYa.mjs} +0 -0
@@ -35,7 +35,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
35
35
  const getSavedPrefs = () => {
36
36
  if (typeof window === "undefined") return {};
37
37
  try {
38
- const raw = localStorage.getItem(PREFERENCES_KEY);
38
+ const raw = window.localStorage.getItem(PREFERENCES_KEY);
39
39
  return raw ? JSON.parse(raw) : {};
40
40
  } catch {
41
41
  return {};
@@ -61,7 +61,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
61
61
  setLocaleState(newL);
62
62
  if (typeof window !== "undefined") try {
63
63
  const prefs = getSavedPrefs();
64
- localStorage.setItem(PREFERENCES_KEY, JSON.stringify({
64
+ window.localStorage.setItem(PREFERENCES_KEY, JSON.stringify({
65
65
  ...prefs,
66
66
  locale: newL
67
67
  }));
@@ -72,7 +72,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
72
72
  setVersionState(newV);
73
73
  if (typeof window !== "undefined") try {
74
74
  const prefs = getSavedPrefs();
75
- localStorage.setItem(PREFERENCES_KEY, JSON.stringify({
75
+ window.localStorage.setItem(PREFERENCES_KEY, JSON.stringify({
76
76
  ...prefs,
77
77
  version: newV
78
78
  }));
@@ -137,6 +137,9 @@ var icons_exports = /* @__PURE__ */ __exportAll({
137
137
  Copy: () => Copy,
138
138
  CornerDownLeft: () => CornerDownLeft,
139
139
  ExternalLink: () => ExternalLink,
140
+ FaceBad: () => FaceBad,
141
+ FaceGood: () => FaceGood,
142
+ FaceRegular: () => FaceRegular,
140
143
  File: () => File,
141
144
  FileText: () => FileText,
142
145
  Hash: () => Hash,
@@ -401,6 +404,71 @@ const FileText = createIcon("FileText", /* @__PURE__ */ jsxs(Fragment, { childre
401
404
  /* @__PURE__ */ jsx("path", { d: "M16 17H8" })
402
405
  ] }));
403
406
  const CornerDownLeft = createIcon("CornerDownLeft", /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("polyline", { points: "9 10 4 15 9 20" }), /* @__PURE__ */ jsx("path", { d: "M20 4v7a4 4 0 0 1-4 4H4" })] }));
407
+ const FaceGood = createIcon("FaceGood", /* @__PURE__ */ jsxs(Fragment, { children: [
408
+ /* @__PURE__ */ jsx("circle", {
409
+ cx: "12",
410
+ cy: "12",
411
+ r: "10"
412
+ }),
413
+ /* @__PURE__ */ jsx("path", { d: "M8 14s1.5 2 4 2 4-2 4-2" }),
414
+ /* @__PURE__ */ jsx("line", {
415
+ x1: "9",
416
+ y1: "9",
417
+ x2: "9.01",
418
+ y2: "9"
419
+ }),
420
+ /* @__PURE__ */ jsx("line", {
421
+ x1: "15",
422
+ y1: "9",
423
+ x2: "15.01",
424
+ y2: "9"
425
+ })
426
+ ] }));
427
+ const FaceRegular = createIcon("FaceRegular", /* @__PURE__ */ jsxs(Fragment, { children: [
428
+ /* @__PURE__ */ jsx("circle", {
429
+ cx: "12",
430
+ cy: "12",
431
+ r: "10"
432
+ }),
433
+ /* @__PURE__ */ jsx("line", {
434
+ x1: "8",
435
+ y1: "15",
436
+ x2: "16",
437
+ y2: "15"
438
+ }),
439
+ /* @__PURE__ */ jsx("line", {
440
+ x1: "9",
441
+ y1: "9",
442
+ x2: "9.01",
443
+ y2: "9"
444
+ }),
445
+ /* @__PURE__ */ jsx("line", {
446
+ x1: "15",
447
+ y1: "9",
448
+ x2: "15.01",
449
+ y2: "9"
450
+ })
451
+ ] }));
452
+ const FaceBad = createIcon("FaceBad", /* @__PURE__ */ jsxs(Fragment, { children: [
453
+ /* @__PURE__ */ jsx("circle", {
454
+ cx: "12",
455
+ cy: "12",
456
+ r: "10"
457
+ }),
458
+ /* @__PURE__ */ jsx("path", { d: "M16 16s-1.5-2-4-2-4 2-4 2" }),
459
+ /* @__PURE__ */ jsx("line", {
460
+ x1: "9",
461
+ y1: "9",
462
+ x2: "9.01",
463
+ y2: "9"
464
+ }),
465
+ /* @__PURE__ */ jsx("line", {
466
+ x1: "15",
467
+ y1: "9",
468
+ x2: "15.01",
469
+ y2: "9"
470
+ })
471
+ ] }));
404
472
 
405
473
  //#endregion
406
474
  //#region src/client/app/routes-context.tsx
@@ -444,7 +512,7 @@ function useRoutes() {
444
512
  const { routes: allRoutes } = useRoutesContext();
445
513
  const config = useConfig();
446
514
  const location = useLocation();
447
- const { hasHydrated, currentLocale: currentLocaleStore, currentVersion: currentVersionStore } = useBoltdocsContext();
515
+ const { currentLocale: currentLocaleStore, currentVersion: currentVersionStore } = useBoltdocsContext();
448
516
  const currentPath = normalizePath(location.pathname);
449
517
  const currentRoute = allRoutes?.find?.((r) => normalizePath(r.path) === currentPath);
450
518
  const currentLocale = config.i18n ? currentLocaleStore || config.i18n.defaultLocale : void 0;
@@ -464,8 +532,9 @@ function useRoutes() {
464
532
  const localeMatch = config.i18n ? (r.locale || config.i18n.defaultLocale) === currentLocale : true;
465
533
  const versionMatch = config.versions ? (r.version || config.versions.defaultVersion) === currentVersion : true;
466
534
  if (!(localeMatch && versionMatch)) return false;
467
- const isCurrentLocalePrefixed = !!currentRoute?.locale;
468
- const isCurrentVersionPrefixed = !!currentRoute?.version;
535
+ const pathParts = location.pathname.split("/").filter(Boolean);
536
+ const isCurrentLocalePrefixed = !!(config.i18n && pathParts.includes(currentLocaleStore || config.i18n.defaultLocale));
537
+ const isCurrentVersionPrefixed = !!(config.versions && pathParts.includes(currentVersionStore || config.versions.defaultVersion));
469
538
  const isRouteLocalePrefixed = !!r.locale;
470
539
  const isRouteVersionPrefixed = !!r.version;
471
540
  const locale = r.locale || defaultLocale;
@@ -483,7 +552,9 @@ function useRoutes() {
483
552
  config,
484
553
  currentLocale,
485
554
  currentVersion,
486
- currentRoute
555
+ location.pathname,
556
+ currentLocaleStore,
557
+ currentVersionStore
487
558
  ]);
488
559
  const collections = useMemo(() => {
489
560
  return new Set((allRoutes || []).map((r) => r.collection).filter(Boolean));
@@ -842,4 +913,4 @@ const BracketsRed = (props) => /* @__PURE__ */ jsxs("svg", {
842
913
  });
843
914
 
844
915
  //#endregion
845
- export { ConfigContext as $, ChevronRight as A, Languages as B, RoutesProvider as C, Check as D, ArrowLeft as E, File as F, Moon as G, Link$2 as H, FileText as I, Search as J, MoreVertical as K, Hash as L, Copy as M, CornerDownLeft as N, ChevronDown as O, ExternalLink as P, icons_exports as Q, Home as R, normalizePath as S, AlertTriangle as T, Menu as U, Lightbulb as V, Monitor as W, TextAlignStart as X, Sun as Y, X as Z, Link$1 as _, Csv as a, useLocalizedTo as b, JavaScript as c, React$1 as d, useConfig as et, Rust as f, Yaml as g, XSocial as h, Css as i, CircleHelp as j, ChevronLeft as k, Json as l, TypeScript as m, BracketsOrange as n, useBoltdocsContext as nt, Discord as o, Shell as p, Pencil as q, BracketsRed as r, Github as s, Bluesky as t, BoltdocsProvider as tt, Markdown as u, NavLink as v, AlertCircle as w, useRoutes as x, cn as y, Info as z };
916
+ export { TextAlignStart as $, ChevronRight as A, Hash as B, RoutesProvider as C, Check as D, ArrowLeft as E, FaceBad as F, Link$2 as G, Info as H, FaceGood as I, Moon as J, Menu as K, FaceRegular as L, Copy as M, CornerDownLeft as N, ChevronDown as O, ExternalLink as P, Sun as Q, File as R, normalizePath as S, AlertTriangle as T, Languages as U, Home as V, Lightbulb as W, Pencil as X, MoreVertical as Y, Search as Z, Link$1 as _, Csv as a, useBoltdocsContext as at, useLocalizedTo as b, JavaScript as c, React$1 as d, X as et, Rust as f, Yaml as g, XSocial as h, Css as i, BoltdocsProvider as it, CircleHelp as j, ChevronLeft as k, Json as l, TypeScript as m, BracketsOrange as n, ConfigContext as nt, Discord as o, Shell as p, Monitor as q, BracketsRed as r, useConfig as rt, Github as s, Bluesky as t, icons_exports as tt, Markdown as u, NavLink as v, AlertCircle as w, useRoutes as x, cn as y, FileText as z };
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- const require_icons_dev = require('./icons-dev-DvJ-hh9x.cjs');
6
+ const require_icons_dev = require('./icons-dev-BryEFkJu.cjs');
7
7
  let react = require("react");
8
8
  react = require_icons_dev.__toESM(react);
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -16,8 +16,16 @@ const THEME_INSTANCE_SYMBOL = Symbol.for("__BDOCS_THEME_INSTANCE__");
16
16
  const THEME_EVENT = "boltdocs-theme-change";
17
17
  const ThemeContext = globalThis[THEME_CONTEXT_SYMBOL] || (globalThis[THEME_CONTEXT_SYMBOL] = (0, react.createContext)(void 0));
18
18
  function ThemeProvider({ children }) {
19
- const [theme, setThemeState] = (0, react.useState)("system");
20
- const [resolvedTheme, setResolvedTheme] = (0, react.useState)("dark");
19
+ const [theme, setThemeState] = (0, react.useState)(() => {
20
+ if (typeof window !== "undefined") try {
21
+ return window.localStorage.getItem("boltdocs-theme") || "system";
22
+ } catch {}
23
+ return "system";
24
+ });
25
+ const [resolvedTheme, setResolvedTheme] = (0, react.useState)(() => {
26
+ if (typeof window !== "undefined" && typeof document !== "undefined" && document.documentElement) return document.documentElement.classList.contains("dark") ? "dark" : "light";
27
+ return "light";
28
+ });
21
29
  const applyTheme = (targetTheme) => {
22
30
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
23
31
  const isDark = targetTheme === "dark" || targetTheme === "system" && mediaQuery.matches;
@@ -27,21 +35,27 @@ function ThemeProvider({ children }) {
27
35
  setResolvedTheme(isDark ? "dark" : "light");
28
36
  };
29
37
  (0, react.useEffect)(() => {
30
- const savedTheme = localStorage.getItem("boltdocs-theme");
31
- if (savedTheme) {
32
- setThemeState(savedTheme);
33
- applyTheme(savedTheme);
34
- } else applyTheme("system");
38
+ try {
39
+ const savedTheme = window.localStorage.getItem("boltdocs-theme");
40
+ if (savedTheme) {
41
+ setThemeState(savedTheme);
42
+ applyTheme(savedTheme);
43
+ } else applyTheme("system");
44
+ } catch {}
35
45
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
36
46
  const listener = () => {
37
- if ((localStorage.getItem("boltdocs-theme") || "system") === "system") applyTheme("system");
47
+ try {
48
+ if ((window.localStorage.getItem("boltdocs-theme") || "system") === "system") applyTheme("system");
49
+ } catch {}
38
50
  };
39
51
  mediaQuery.addEventListener("change", listener);
40
52
  return () => mediaQuery.removeEventListener("change", listener);
41
53
  }, []);
42
54
  const setTheme = (newTheme) => {
43
55
  setThemeState(newTheme);
44
- localStorage.setItem("boltdocs-theme", newTheme);
56
+ try {
57
+ window.localStorage.setItem("boltdocs-theme", newTheme);
58
+ } catch {}
45
59
  applyTheme(newTheme);
46
60
  if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }));
47
61
  };
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { H as Link, _ as Link$1, y as cn } from "./icons-dev-Oju24Wjp.js";
6
+ import { G as Link, _ as Link$1, y as cn } from "./icons-dev-kJyGWNeg.js";
7
7
  import * as React$1 from "react";
8
8
  import { createContext, use, useEffect, useState } from "react";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -15,8 +15,16 @@ const THEME_INSTANCE_SYMBOL = Symbol.for("__BDOCS_THEME_INSTANCE__");
15
15
  const THEME_EVENT = "boltdocs-theme-change";
16
16
  const ThemeContext = globalThis[THEME_CONTEXT_SYMBOL] || (globalThis[THEME_CONTEXT_SYMBOL] = createContext(void 0));
17
17
  function ThemeProvider({ children }) {
18
- const [theme, setThemeState] = useState("system");
19
- const [resolvedTheme, setResolvedTheme] = useState("dark");
18
+ const [theme, setThemeState] = useState(() => {
19
+ if (typeof window !== "undefined") try {
20
+ return window.localStorage.getItem("boltdocs-theme") || "system";
21
+ } catch {}
22
+ return "system";
23
+ });
24
+ const [resolvedTheme, setResolvedTheme] = useState(() => {
25
+ if (typeof window !== "undefined" && typeof document !== "undefined" && document.documentElement) return document.documentElement.classList.contains("dark") ? "dark" : "light";
26
+ return "light";
27
+ });
20
28
  const applyTheme = (targetTheme) => {
21
29
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
22
30
  const isDark = targetTheme === "dark" || targetTheme === "system" && mediaQuery.matches;
@@ -26,21 +34,27 @@ function ThemeProvider({ children }) {
26
34
  setResolvedTheme(isDark ? "dark" : "light");
27
35
  };
28
36
  useEffect(() => {
29
- const savedTheme = localStorage.getItem("boltdocs-theme");
30
- if (savedTheme) {
31
- setThemeState(savedTheme);
32
- applyTheme(savedTheme);
33
- } else applyTheme("system");
37
+ try {
38
+ const savedTheme = window.localStorage.getItem("boltdocs-theme");
39
+ if (savedTheme) {
40
+ setThemeState(savedTheme);
41
+ applyTheme(savedTheme);
42
+ } else applyTheme("system");
43
+ } catch {}
34
44
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
35
45
  const listener = () => {
36
- if ((localStorage.getItem("boltdocs-theme") || "system") === "system") applyTheme("system");
46
+ try {
47
+ if ((window.localStorage.getItem("boltdocs-theme") || "system") === "system") applyTheme("system");
48
+ } catch {}
37
49
  };
38
50
  mediaQuery.addEventListener("change", listener);
39
51
  return () => mediaQuery.removeEventListener("change", listener);
40
52
  }, []);
41
53
  const setTheme = (newTheme) => {
42
54
  setThemeState(newTheme);
43
- localStorage.setItem("boltdocs-theme", newTheme);
55
+ try {
56
+ window.localStorage.setItem("boltdocs-theme", newTheme);
57
+ } catch {}
44
58
  applyTheme(newTheme);
45
59
  if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }));
46
60
  };
@@ -3,8 +3,8 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { D as Check, F as File, M as Copy, T as AlertTriangle, V as Lightbulb, _ as Link, a as Csv, c as JavaScript, d as React$1, f as Rust, g as Yaml, i as Css, l as Json, m as TypeScript, n as BracketsOrange, p as Shell, r as BracketsRed, u as Markdown, w as AlertCircle, y as cn, z as Info } from "./icons-dev-Oju24Wjp.js";
7
- import { a as CodeBlockGroup, i as CodeBlockContent, l as useTheme, n as Tooltip, o as CodeBlockHeader, r as CodeBlock$1, s as Heading$1, t as Image$1 } from "./image-Do8V9PCW.js";
6
+ import { D as Check, H as Info, M as Copy, R as File, T as AlertTriangle, W as Lightbulb, _ as Link, a as Csv, c as JavaScript, d as React$1, f as Rust, g as Yaml, i as Css, l as Json, m as TypeScript, n as BracketsOrange, p as Shell, r as BracketsRed, rt as useConfig, u as Markdown, w as AlertCircle, y as cn } from "./icons-dev-kJyGWNeg.js";
7
+ import { a as CodeBlockGroup, i as CodeBlockContent, l as useTheme, n as Tooltip, o as CodeBlockHeader, r as CodeBlock$1, s as Heading$1, t as Image$1 } from "./image-CjYu9Eml.js";
8
8
  import { useCallback, useEffect, useRef, useState } from "react";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  import { Button } from "react-aria-components";
@@ -248,12 +248,66 @@ const copyToClipboard = async (text) => {
248
248
 
249
249
  //#endregion
250
250
  //#region src/client/components/mdx/use-code-block.ts
251
+ const langIconMap = {
252
+ ts: TypeScript,
253
+ tsx: React$1,
254
+ js: JavaScript,
255
+ jsx: React$1,
256
+ json: Json,
257
+ css: Css,
258
+ html: BracketsOrange,
259
+ md: Markdown,
260
+ mdx: Markdown,
261
+ bash: Shell,
262
+ sh: Shell,
263
+ yaml: Yaml,
264
+ yml: Yaml,
265
+ rs: Rust,
266
+ rust: Rust,
267
+ toml: BracketsRed,
268
+ csv: Csv
269
+ };
251
270
  function useCodeBlock(props) {
252
271
  const [copied, setCopied] = useState(false);
253
272
  const [isExpanded, setIsExpanded] = useState(false);
254
273
  const [isExpandable, setIsExpandable] = useState(false);
255
274
  const preRef = useRef(null);
256
275
  const timerRef = useRef(null);
276
+ const [rated, setRated] = useState(null);
277
+ const customConfig = useConfig().integrations?.feedback?.custom;
278
+ const showCodeBlockFeedback = !!(customConfig?.enabled && !props.plain);
279
+ const lang = props.lang || props["data-lang"] || "";
280
+ const isHighlighted = props["data-highlighted"] === "true" || typeof props.className === "string" && props.className.includes("shiki");
281
+ const rawHighlightedHtml = props.highlightedHtml || props["data-highlighted-html"];
282
+ const effectiveHighlightedHtml = typeof rawHighlightedHtml === "string" ? rawHighlightedHtml.replace(/<span class="line">\s*(?:<span[^>]*>\s*<\/span>)?\s*<\/span>\s*(<\/code>\s*<\/pre>)/g, "$1") : rawHighlightedHtml;
283
+ const effectiveTitle = props.title || props["data-title"];
284
+ const handleRate = useCallback(async (type) => {
285
+ if (rated) return;
286
+ setRated(type);
287
+ try {
288
+ const code = preRef.current?.textContent ?? "";
289
+ const snippet = code.trim().slice(0, 100) + (code.length > 100 ? "..." : "");
290
+ const blockId = `Code Block (${lang || "plain"}): \`${snippet}\``;
291
+ const endpoint = customConfig?.endpoint || "/api/feedback";
292
+ await fetch(endpoint, {
293
+ method: "POST",
294
+ headers: { "Content-Type": "application/json" },
295
+ body: JSON.stringify({
296
+ rating: type === "up" ? "good" : "bad",
297
+ comment: `Rated code block: ${type === "up" ? "Helpful" : "Unhelpful"}`,
298
+ path: window.location.pathname,
299
+ title: document.title,
300
+ blockId
301
+ })
302
+ });
303
+ } catch (err) {
304
+ console.error("Failed to submit code block feedback:", err);
305
+ }
306
+ }, [
307
+ rated,
308
+ lang,
309
+ customConfig?.endpoint
310
+ ]);
257
311
  useEffect(() => {
258
312
  return () => {
259
313
  if (timerRef.current) clearTimeout(timerRef.current);
@@ -272,6 +326,7 @@ function useCodeBlock(props) {
272
326
  const lines = (preRef.current?.textContent ?? "").trim().split("\n").length;
273
327
  setIsExpandable(lines > 6);
274
328
  }, [props.children, props.highlightedHtml]);
329
+ const LangIcon = langIconMap[lang] || File;
275
330
  return {
276
331
  copied,
277
332
  isExpanded,
@@ -279,31 +334,20 @@ function useCodeBlock(props) {
279
334
  isExpandable,
280
335
  preRef,
281
336
  handleCopy,
282
- shouldTruncate: isExpandable && !isExpanded
337
+ shouldTruncate: isExpandable && !isExpanded,
338
+ isHighlighted,
339
+ effectiveHighlightedHtml,
340
+ effectiveTitle,
341
+ lang,
342
+ showCodeBlockFeedback,
343
+ rated,
344
+ handleRate,
345
+ LangIcon
283
346
  };
284
347
  }
285
348
 
286
349
  //#endregion
287
350
  //#region src/client/components/mdx/code-block.tsx
288
- const langIconMap = {
289
- ts: TypeScript,
290
- tsx: React$1,
291
- js: JavaScript,
292
- jsx: React$1,
293
- json: Json,
294
- css: Css,
295
- html: BracketsOrange,
296
- md: Markdown,
297
- mdx: Markdown,
298
- bash: Shell,
299
- sh: Shell,
300
- yaml: Yaml,
301
- yml: Yaml,
302
- rs: Rust,
303
- rust: Rust,
304
- toml: BracketsRed,
305
- csv: Csv
306
- };
307
351
  const CopyButton = ({ copied, handleCopy }) => {
308
352
  return /* @__PURE__ */ jsx(Tooltip, {
309
353
  content: copied ? "Copied!" : "Copy code",
@@ -315,16 +359,52 @@ const CopyButton = ({ copied, handleCopy }) => {
315
359
  })
316
360
  });
317
361
  };
362
+ const CodeBlockFeedback = ({ rated, onRate }) => {
363
+ return /* @__PURE__ */ jsxs("div", {
364
+ className: "flex items-center gap-0.5 border-r border-subtle pr-1.5 mr-1",
365
+ children: [/* @__PURE__ */ jsx(Tooltip, {
366
+ content: rated === "up" ? "Helpful!" : "This code is helpful",
367
+ children: /* @__PURE__ */ jsx(Button, {
368
+ onPress: () => onRate("up"),
369
+ disabled: rated !== null,
370
+ className: cn("grid place-items-center size-8 bg-transparent outline-none cursor-pointer transition-all duration-200 hover:scale-110 active:scale-95 [&>svg]:size-4 [&>svg]:stroke-2 z-10", rated === "up" ? "text-emerald-500 dark:text-emerald-400" : rated === "down" ? "opacity-30 cursor-not-allowed text-muted" : "text-muted hover:text-body"),
371
+ "aria-label": "Mark as helpful",
372
+ children: /* @__PURE__ */ jsx("svg", {
373
+ xmlns: "http://www.w3.org/2000/svg",
374
+ viewBox: "0 0 24 24",
375
+ fill: "none",
376
+ stroke: "currentColor",
377
+ strokeWidth: "2",
378
+ strokeLinecap: "round",
379
+ strokeLinejoin: "round",
380
+ children: /* @__PURE__ */ jsx("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" })
381
+ })
382
+ })
383
+ }), /* @__PURE__ */ jsx(Tooltip, {
384
+ content: rated === "down" ? "Unhelpful" : "This code is unhelpful",
385
+ children: /* @__PURE__ */ jsx(Button, {
386
+ onPress: () => onRate("down"),
387
+ disabled: rated !== null,
388
+ className: cn("grid place-items-center size-8 bg-transparent outline-none cursor-pointer transition-all duration-200 hover:scale-110 active:scale-95 [&>svg]:size-4 [&>svg]:stroke-2 z-10", rated === "down" ? "text-rose-500 dark:text-rose-400" : rated === "up" ? "opacity-30 cursor-not-allowed text-muted" : "text-muted hover:text-body"),
389
+ "aria-label": "Mark as unhelpful",
390
+ children: /* @__PURE__ */ jsx("svg", {
391
+ xmlns: "http://www.w3.org/2000/svg",
392
+ viewBox: "0 0 24 24",
393
+ fill: "none",
394
+ stroke: "currentColor",
395
+ strokeWidth: "2",
396
+ strokeLinecap: "round",
397
+ strokeLinejoin: "round",
398
+ children: /* @__PURE__ */ jsx("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h3a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-3" })
399
+ })
400
+ })
401
+ })]
402
+ });
403
+ };
318
404
  function CodeBlock(props) {
319
405
  const { children, hideCopy = false, highlightedHtml, "data-highlighted-html": dataHighlightedHtml, title, "data-title": dataTitle, "data-lang": dataLang, plain = false, lineNumbers, showLineNumbers, wordWrap, "word-wrap": wordWrapHyphen, metastring, ...rest } = props;
320
406
  const { className: shikiClassName, ...cleanRest } = rest;
321
- const isHighlighted = props["data-highlighted"] === "true" || typeof shikiClassName === "string" && shikiClassName.includes("shiki");
322
- const rawHighlightedHtml = highlightedHtml || dataHighlightedHtml;
323
- const effectiveHighlightedHtml = typeof rawHighlightedHtml === "string" ? rawHighlightedHtml.replace(/<span class="line">\s*(?:<span[^>]*>\s*<\/span>)?\s*<\/span>\s*(<\/code>\s*<\/pre>)/g, "$1") : rawHighlightedHtml;
324
- const effectiveTitle = title || dataTitle;
325
- const lang = props.lang || dataLang || "";
326
- const { copied, isExpanded, setIsExpanded, isExpandable, preRef, handleCopy, shouldTruncate } = useCodeBlock(props);
327
- const LangIcon = langIconMap[lang];
407
+ const { copied, isExpanded, setIsExpanded, isExpandable, preRef, handleCopy, shouldTruncate, isHighlighted, effectiveHighlightedHtml, effectiveTitle, showCodeBlockFeedback, rated, handleRate, LangIcon } = useCodeBlock(props);
328
408
  return /* @__PURE__ */ jsxs(CodeBlock$1, {
329
409
  plain,
330
410
  className: props.className,
@@ -333,12 +413,15 @@ function CodeBlock(props) {
333
413
  children: [/* @__PURE__ */ jsx(CodeBlockGroup, { children: effectiveTitle && /* @__PURE__ */ jsxs(Fragment, { children: [LangIcon ? /* @__PURE__ */ jsx(LangIcon, { size: 14 }) : /* @__PURE__ */ jsx(File, {
334
414
  size: 14,
335
415
  className: "opacity-60"
336
- }), /* @__PURE__ */ jsx("span", { children: effectiveTitle })] }) }), /* @__PURE__ */ jsx("div", {
416
+ }), /* @__PURE__ */ jsx("span", { children: effectiveTitle })] }) }), /* @__PURE__ */ jsxs("div", {
337
417
  className: "flex items-center gap-1",
338
- children: !hideCopy && /* @__PURE__ */ jsx(CopyButton, {
418
+ children: [showCodeBlockFeedback && /* @__PURE__ */ jsx(CodeBlockFeedback, {
419
+ rated,
420
+ onRate: handleRate
421
+ }), !hideCopy && /* @__PURE__ */ jsx(CopyButton, {
339
422
  copied,
340
423
  handleCopy
341
- })
424
+ })]
342
425
  })]
343
426
  }), /* @__PURE__ */ jsxs(CodeBlockContent, {
344
427
  shouldTruncate,
@@ -521,4 +604,4 @@ const mdx_components_default = {
521
604
  };
522
605
 
523
606
  //#endregion
524
- export { copyToClipboard as n, mdx_components_default as t };
607
+ export { useCodeBlock as n, copyToClipboard as r, mdx_components_default as t };