@djangocfg/ui-tools 2.1.318 → 2.1.319

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 (28) hide show
  1. package/dist/{DocsLayout-ESVQZO3V.mjs → DocsLayout-CTJINVBM.mjs} +235 -267
  2. package/dist/DocsLayout-CTJINVBM.mjs.map +1 -0
  3. package/dist/{DocsLayout-KUPDWJ3G.cjs → DocsLayout-XLDB6CJ2.cjs} +273 -305
  4. package/dist/DocsLayout-XLDB6CJ2.cjs.map +1 -0
  5. package/dist/{chunk-GBLQTHWT.mjs → chunk-62Y65TGK.mjs} +5 -4
  6. package/dist/chunk-62Y65TGK.mjs.map +1 -0
  7. package/dist/{chunk-S44PW6NK.cjs → chunk-TKSFZHCG.cjs} +5 -4
  8. package/dist/chunk-TKSFZHCG.cjs.map +1 -0
  9. package/dist/index.cjs +10 -10
  10. package/dist/index.mjs +4 -4
  11. package/package.json +6 -6
  12. package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +30 -0
  13. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +35 -50
  14. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/index.tsx +49 -22
  15. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/index.tsx +1 -1
  16. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/index.ts +10 -11
  17. package/src/tools/OpenapiViewer/components/DocsLayout/SchemaCopyMenu.tsx +25 -5
  18. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/BrandHeader.tsx +18 -33
  19. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/Toolbar.tsx +40 -24
  20. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/index.tsx +8 -14
  21. package/src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts +1 -4
  22. package/src/tools/OpenapiViewer/utils/operationToHar.ts +2 -1
  23. package/src/tools/OpenapiViewer/utils/url.ts +9 -2
  24. package/dist/DocsLayout-ESVQZO3V.mjs.map +0 -1
  25. package/dist/DocsLayout-KUPDWJ3G.cjs.map +0 -1
  26. package/dist/chunk-GBLQTHWT.mjs.map +0 -1
  27. package/dist/chunk-S44PW6NK.cjs.map +0 -1
  28. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/MethodChips.tsx +0 -43
@@ -1,13 +1,13 @@
1
- import { deduplicateEndpoints, dereferenceSchema, resolveBaseUrl, usePlaygroundContext, toMarkdown, toCompactJson, toRawJson, formatBytes, MarkdownMessage, CODE_SAMPLE_TARGETS, buildHarRequest, resolveAbsolute, renderSnippet, PrettyCode_default, relativePath, endpointToMarkdown, isValidJson, findApiKeyById, parseRequestHeaders, UrlBuilder, sampleSchemaJson, joinUrl } from './chunk-GBLQTHWT.mjs';
1
+ import { deduplicateEndpoints, dereferenceSchema, resolveBaseUrl, usePlaygroundContext, relativePath, toMarkdown, toCompactJson, toRawJson, formatBytes, MarkdownMessage, CODE_SAMPLE_TARGETS, buildHarRequest, resolveAbsolute, renderSnippet, PrettyCode_default, endpointToMarkdown, isValidJson, findApiKeyById, parseRequestHeaders, UrlBuilder, sampleSchemaJson, joinUrl } from './chunk-62Y65TGK.mjs';
2
2
  import { JsonTree_default } from './chunk-LFWQ36LJ.mjs';
3
3
  import './chunk-SSUOENAZ.mjs';
4
4
  import { __name } from './chunk-CGILA3WO.mjs';
5
5
  import React12, { useRef, useEffect, createContext, useCallback, useMemo, useState, useContext } from 'react';
6
6
  import { groupBy, orderBy, partition, sortBy, keyBy } from 'lodash-es';
7
- import { Tooltip, TooltipTrigger, TooltipContent, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, Input, Combobox, SafeTooltipProvider, CopyButton, Switch, Textarea, SidePanel, ResponsiveSheet, ResponsiveSheetContent, ResponsiveSheetHeader, ResponsiveSheetTitle, Skeleton, TooltipProvider } from '@djangocfg/ui-core/components';
7
+ import { Tooltip, TooltipTrigger, TooltipContent, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, Input, SafeTooltipProvider, CopyButton, Switch, Combobox, Textarea, SidePanel, ResponsiveSheet, ResponsiveSheetContent, ResponsiveSheetHeader, ResponsiveSheetTitle, Skeleton, TooltipProvider } from '@djangocfg/ui-core/components';
8
8
  import { toast, useMediaQuery } from '@djangocfg/ui-core/hooks';
9
9
  import consola from 'consola';
10
- import { ChevronRight, Sparkles, ChevronDown, Check, Search, X, Link2, FileCode2, ChevronsDownUp, ChevronsUpDown, Play, Minus, Plus, RotateCcw, Send, Key, Terminal, Info, ShieldCheck, Loader2, WifiOff, AlertCircle } from 'lucide-react';
10
+ import { ChevronRight, Sparkles, ChevronDown, Check, Search, X, Play, Link2, Minus, Plus, RotateCcw, Send, Key, Terminal, Info, ShieldCheck, Loader2, WifiOff, AlertCircle, ChevronsDownUp, ChevronsUpDown } from 'lucide-react';
11
11
  import { cn } from '@djangocfg/ui-core/lib';
12
12
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
13
  import { create } from 'zustand';
@@ -590,142 +590,20 @@ function CollapsibleSection({
590
590
  ] });
591
591
  }
592
592
  __name(CollapsibleSection, "CollapsibleSection");
593
- var FLAVOUR_LABELS = {
594
- markdown: {
595
- title: "Markdown for LLM",
596
- hint: "Endpoints + params as prose. Smallest."
597
- },
598
- compact: {
599
- title: "Compact JSON",
600
- hint: "Dereferenced, no examples, minified."
601
- },
602
- raw: {
603
- title: "Raw JSON",
604
- hint: "Full OpenAPI document with $refs."
605
- }
606
- };
607
- function SchemaCopyMenu({ schema, endpoints, baseUrl, variant = "button" }) {
608
- const [sizeCache, setSizeCache] = useState({});
609
- const [justCopied, setJustCopied] = useState(null);
610
- const [open, setOpen] = useState(false);
611
- const isReady = schema !== null && endpoints.length > 0;
612
- const build = useCallback(
613
- (flavour) => {
614
- if (!schema) return "";
615
- if (flavour === "markdown") return toMarkdown(schema, endpoints, baseUrl);
616
- if (flavour === "compact") return toCompactJson(schema, baseUrl);
617
- return toRawJson(schema, baseUrl);
618
- },
619
- [schema, endpoints, baseUrl]
620
- );
621
- const handleCopy = useCallback(
622
- async (flavour) => {
623
- if (!isReady) return;
624
- const text = build(flavour);
625
- const label = FLAVOUR_LABELS[flavour].title;
626
- try {
627
- await navigator.clipboard.writeText(text);
628
- const size = formatBytes(text);
629
- setSizeCache((prev) => ({ ...prev, [flavour]: size }));
630
- setJustCopied(flavour);
631
- setTimeout(() => setJustCopied(null), 1500);
632
- setOpen(false);
633
- toast.success(`Copied ${label}`, { description: size });
634
- } catch (err) {
635
- const message = err instanceof Error ? err.message : "Clipboard permission denied";
636
- toast.error("Copy failed", { description: message });
637
- }
638
- },
639
- [build, isReady]
640
- );
641
- const flavours = useMemo(() => ["markdown", "compact", "raw"], []);
642
- return /* @__PURE__ */ jsxs(DropdownMenu, { open, onOpenChange: setOpen, children: [
643
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: variant === "icon" ? /* @__PURE__ */ jsx(
644
- Button,
645
- {
646
- variant: "ghost",
647
- size: "icon",
648
- className: "h-7 w-7 shrink-0",
649
- disabled: !isReady,
650
- title: "Copy schema for AI",
651
- "aria-label": "Copy schema for AI",
652
- children: /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" })
653
- }
654
- ) : /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: !isReady, children: [
655
- /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" }),
656
- "Copy for AI",
657
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 opacity-60" })
658
- ] }) }),
659
- /* @__PURE__ */ jsxs(
660
- DropdownMenuContent,
661
- {
662
- side: "right",
663
- align: "start",
664
- sideOffset: 6,
665
- collisionPadding: 8,
666
- className: "w-60 max-w-[calc(100vw-16px)]",
667
- children: [
668
- /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Copy schema" }),
669
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
670
- flavours.map((f) => {
671
- const label = FLAVOUR_LABELS[f];
672
- const size = sizeCache[f];
673
- const isDone = justCopied === f;
674
- return /* @__PURE__ */ jsxs(
675
- DropdownMenuItem,
676
- {
677
- onClick: (e) => {
678
- e.preventDefault();
679
- void handleCopy(f);
680
- },
681
- className: "flex flex-col items-start gap-0.5 py-2 cursor-pointer",
682
- children: [
683
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2", children: [
684
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium flex-1", children: label.title }),
685
- isDone ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] text-emerald-500", children: [
686
- /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
687
- " Copied"
688
- ] }) : size ? /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono text-muted-foreground/70 tabular-nums", children: size }) : null
689
- ] }),
690
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70 leading-snug line-clamp-1", children: label.hint })
691
- ]
692
- },
693
- f
694
- );
695
- })
696
- ]
697
- }
698
- )
699
- ] });
700
- }
701
- __name(SchemaCopyMenu, "SchemaCopyMenu");
702
- function BrandHeader({ info, endpoints, rawSchema, resolvedBaseUrl }) {
593
+ function BrandHeader({ info }) {
703
594
  const apiTitle = info?.title ?? "API Reference";
704
- const copyReady = rawSchema !== null && rawSchema !== void 0 && endpoints.length > 0;
705
- return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-2.5 flex items-start gap-2", children: [
706
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
707
- /* @__PURE__ */ jsx(
708
- "div",
709
- {
710
- className: "text-[13px] font-semibold text-foreground leading-tight truncate",
711
- title: apiTitle,
712
- children: apiTitle
713
- }
714
- ),
715
- info?.version && /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] text-muted-foreground/60 leading-tight mt-0.5", children: [
716
- "v",
717
- info.version
718
- ] })
719
- ] }),
720
- copyReady && /* @__PURE__ */ jsx(
721
- SchemaCopyMenu,
595
+ const versionLabel = info?.version ? `v${info.version}` : null;
596
+ const versionNode = versionLabel ? /* @__PURE__ */ jsx("div", { className: "font-mono text-[10px] text-muted-foreground/60 leading-tight mt-0.5", children: versionLabel }) : null;
597
+ return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-2.5", children: [
598
+ /* @__PURE__ */ jsx(
599
+ "div",
722
600
  {
723
- schema: rawSchema ?? null,
724
- endpoints,
725
- baseUrl: resolvedBaseUrl,
726
- variant: "icon"
601
+ className: "text-[13px] font-semibold text-foreground leading-tight truncate",
602
+ title: apiTitle,
603
+ children: apiTitle
727
604
  }
728
- )
605
+ ),
606
+ versionNode
729
607
  ] });
730
608
  }
731
609
  __name(BrandHeader, "BrandHeader");
@@ -755,19 +633,11 @@ function sidebarLabel(ep, groupCommonPrefix) {
755
633
  const tail = ep.path.slice(groupCommonPrefix.length) || "/";
756
634
  return tail;
757
635
  }
758
- return relativePath2(ep.path);
636
+ return relativePath(ep.path);
759
637
  }
760
638
  __name(sidebarLabel, "sidebarLabel");
761
- function relativePath2(full) {
762
- try {
763
- return new URL(full).pathname;
764
- } catch {
765
- return full;
766
- }
767
- }
768
- __name(relativePath2, "relativePath");
769
639
  function sidebarTooltip(ep) {
770
- return `${ep.method} ${relativePath2(ep.path)}`;
640
+ return `${ep.method} ${relativePath(ep.path)}`;
771
641
  }
772
642
  __name(sidebarTooltip, "sidebarTooltip");
773
643
 
@@ -951,29 +821,130 @@ function SidebarBody({ body, onNavigate }) {
951
821
  return /* @__PURE__ */ jsx("nav", { className: "py-1.5", children: body.sections.map((section) => /* @__PURE__ */ jsx(SchemaSection, { section, onNavigate }, section.sourceId)) });
952
822
  }
953
823
  __name(SidebarBody, "SidebarBody");
954
-
955
- // src/tools/OpenapiViewer/components/DocsLayout/Sidebar/types.ts
956
- var METHOD_FILTERS = ["ALL", "GET", "POST", "PUT", "PATCH", "DELETE"];
957
- function MethodChips({ value, onChange }) {
958
- return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 overflow-x-auto -mx-1 px-1 pb-px", children: METHOD_FILTERS.map((m) => {
959
- const active = value === m;
960
- return /* @__PURE__ */ jsx(
961
- "button",
824
+ var FLAVOUR_LABELS = {
825
+ markdown: {
826
+ title: "Markdown for LLM",
827
+ hint: "Endpoints + params as prose. Smallest."
828
+ },
829
+ compact: {
830
+ title: "Compact JSON",
831
+ hint: "Dereferenced, no examples, minified."
832
+ },
833
+ raw: {
834
+ title: "Raw JSON",
835
+ hint: "Full OpenAPI document with $refs."
836
+ }
837
+ };
838
+ function SchemaCopyMenu({ schema, endpoints, baseUrl, variant = "button", side }) {
839
+ const [sizeCache, setSizeCache] = useState({});
840
+ const [justCopied, setJustCopied] = useState(null);
841
+ const [open, setOpen] = useState(false);
842
+ const isReady = schema !== null && endpoints.length > 0;
843
+ const build = useCallback(
844
+ (flavour) => {
845
+ if (!schema) return "";
846
+ if (flavour === "markdown") return toMarkdown(schema, endpoints, baseUrl);
847
+ if (flavour === "compact") return toCompactJson(schema, baseUrl);
848
+ return toRawJson(schema, baseUrl);
849
+ },
850
+ [schema, endpoints, baseUrl]
851
+ );
852
+ const handleCopy = useCallback(
853
+ async (flavour) => {
854
+ if (!isReady) return;
855
+ const text = build(flavour);
856
+ const label = FLAVOUR_LABELS[flavour].title;
857
+ try {
858
+ await navigator.clipboard.writeText(text);
859
+ const size = formatBytes(text);
860
+ setSizeCache((prev) => ({ ...prev, [flavour]: size }));
861
+ setJustCopied(flavour);
862
+ setTimeout(() => setJustCopied(null), 1500);
863
+ setOpen(false);
864
+ toast.success(`Copied ${label}`, { description: size });
865
+ } catch (err) {
866
+ const message = err instanceof Error ? err.message : "Clipboard permission denied";
867
+ toast.error("Copy failed", { description: message });
868
+ }
869
+ },
870
+ [build, isReady]
871
+ );
872
+ const flavours = useMemo(() => ["markdown", "compact", "raw"], []);
873
+ const resolvedSide = side ?? (variant === "footer" ? "top" : "right");
874
+ const resolvedAlign = variant === "footer" ? "center" : "start";
875
+ return /* @__PURE__ */ jsxs(DropdownMenu, { open, onOpenChange: setOpen, children: [
876
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: variant === "icon" ? /* @__PURE__ */ jsx(
877
+ Button,
962
878
  {
963
- type: "button",
964
- onClick: () => onChange(m),
965
- "aria-pressed": active,
966
- className: cn(
967
- "shrink-0 px-2 h-6 rounded font-mono text-[10px] font-semibold tracking-wide uppercase transition-colors",
968
- active ? "bg-foreground text-background" : "text-muted-foreground/70 hover:text-foreground hover:bg-muted"
969
- ),
970
- children: m
971
- },
972
- m
973
- );
974
- }) });
879
+ variant: "ghost",
880
+ size: "icon",
881
+ className: "h-7 w-7 shrink-0",
882
+ disabled: !isReady,
883
+ title: "Copy schema for AI",
884
+ "aria-label": "Copy schema for AI",
885
+ children: /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" })
886
+ }
887
+ ) : variant === "footer" ? /* @__PURE__ */ jsxs(
888
+ Button,
889
+ {
890
+ variant: "secondary",
891
+ size: "sm",
892
+ className: "w-full justify-center gap-1.5 text-xs",
893
+ disabled: !isReady,
894
+ children: [
895
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" }),
896
+ "Copy schema for AI",
897
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 opacity-60" })
898
+ ]
899
+ }
900
+ ) : /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: !isReady, children: [
901
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" }),
902
+ "Copy for AI",
903
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 opacity-60" })
904
+ ] }) }),
905
+ /* @__PURE__ */ jsxs(
906
+ DropdownMenuContent,
907
+ {
908
+ side: resolvedSide,
909
+ align: resolvedAlign,
910
+ sideOffset: 6,
911
+ collisionPadding: 8,
912
+ className: "w-60 max-w-[calc(100vw-16px)]",
913
+ children: [
914
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Copy schema" }),
915
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
916
+ flavours.map((f) => {
917
+ const label = FLAVOUR_LABELS[f];
918
+ const size = sizeCache[f];
919
+ const isDone = justCopied === f;
920
+ return /* @__PURE__ */ jsxs(
921
+ DropdownMenuItem,
922
+ {
923
+ onClick: (e) => {
924
+ e.preventDefault();
925
+ void handleCopy(f);
926
+ },
927
+ className: "flex flex-col items-start gap-0.5 py-2 cursor-pointer",
928
+ children: [
929
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2", children: [
930
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium flex-1", children: label.title }),
931
+ isDone ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] text-emerald-500", children: [
932
+ /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
933
+ " Copied"
934
+ ] }) : size ? /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono text-muted-foreground/70 tabular-nums", children: size }) : null
935
+ ] }),
936
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70 leading-snug line-clamp-1", children: label.hint })
937
+ ]
938
+ },
939
+ f
940
+ );
941
+ })
942
+ ]
943
+ }
944
+ )
945
+ ] });
975
946
  }
976
- __name(MethodChips, "MethodChips");
947
+ __name(SchemaCopyMenu, "SchemaCopyMenu");
977
948
  function SearchInput({ value, onChange, placeholder }) {
978
949
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
979
950
  /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none" }),
@@ -1010,28 +981,41 @@ function Toolbar({
1010
981
  showSchemaSelector,
1011
982
  search,
1012
983
  onSearchChange,
1013
- methodFilter,
1014
- onMethodFilterChange
984
+ endpoints,
985
+ rawSchema,
986
+ resolvedBaseUrl
1015
987
  }) {
1016
988
  const schemaOptions = React12.useMemo(
1017
989
  () => schemas.map((s) => ({ value: s.id, label: s.name })),
1018
990
  [schemas]
1019
991
  );
992
+ const copyReady = rawSchema !== null && rawSchema !== void 0 && endpoints.length > 0;
993
+ const schemaSelectorNode = showSchemaSelector ? /* @__PURE__ */ jsx(
994
+ Combobox,
995
+ {
996
+ options: schemaOptions,
997
+ value: currentSchemaId ?? "",
998
+ onValueChange: (id) => id && onSchemaChange(id),
999
+ placeholder: "Select API",
1000
+ searchPlaceholder: "Search APIs\u2026",
1001
+ emptyText: "No APIs found",
1002
+ className: "w-full h-8 text-xs"
1003
+ }
1004
+ ) : null;
1005
+ const copyMenuNode = copyReady ? /* @__PURE__ */ jsx(
1006
+ SchemaCopyMenu,
1007
+ {
1008
+ schema: rawSchema ?? null,
1009
+ endpoints,
1010
+ baseUrl: resolvedBaseUrl,
1011
+ variant: "footer",
1012
+ side: "bottom"
1013
+ }
1014
+ ) : null;
1020
1015
  return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-2.5 space-y-2", children: [
1021
- showSchemaSelector && /* @__PURE__ */ jsx(
1022
- Combobox,
1023
- {
1024
- options: schemaOptions,
1025
- value: currentSchemaId ?? "",
1026
- onValueChange: (id) => id && onSchemaChange(id),
1027
- placeholder: "Select API",
1028
- searchPlaceholder: "Search APIs\u2026",
1029
- emptyText: "No APIs found",
1030
- className: "w-full h-8 text-xs"
1031
- }
1032
- ),
1016
+ schemaSelectorNode,
1033
1017
  /* @__PURE__ */ jsx(SearchInput, { value: search, onChange: onSearchChange }),
1034
- /* @__PURE__ */ jsx(MethodChips, { value: methodFilter, onChange: onMethodFilterChange })
1018
+ copyMenuNode
1035
1019
  ] });
1036
1020
  }
1037
1021
  __name(Toolbar, "Toolbar");
@@ -1059,7 +1043,6 @@ function DocsSidebar({
1059
1043
  resolvedBaseUrl
1060
1044
  }) {
1061
1045
  const [search, setSearch] = useState("");
1062
- const [methodFilter, setMethodFilter] = useState("ALL");
1063
1046
  const debouncedSearch = useDebouncedValue(search);
1064
1047
  const body = useMemo(() => {
1065
1048
  if (grouping === "sections") {
@@ -1068,7 +1051,7 @@ function DocsSidebar({
1068
1051
  endpointsBySchema ?? {},
1069
1052
  selectedVersion,
1070
1053
  debouncedSearch,
1071
- methodFilter,
1054
+ "ALL",
1072
1055
  activeEndpointId
1073
1056
  );
1074
1057
  }
@@ -1076,7 +1059,7 @@ function DocsSidebar({
1076
1059
  endpoints,
1077
1060
  selectedVersion,
1078
1061
  debouncedSearch,
1079
- methodFilter,
1062
+ "ALL",
1080
1063
  activeEndpointId
1081
1064
  );
1082
1065
  }, [
@@ -1086,21 +1069,12 @@ function DocsSidebar({
1086
1069
  endpoints,
1087
1070
  selectedVersion,
1088
1071
  debouncedSearch,
1089
- methodFilter,
1090
1072
  activeEndpointId
1091
1073
  ]);
1092
1074
  const hasMultipleSchemas = schemas.length > 1;
1093
1075
  const showSchemaSelector = grouping === "selector" && hasMultipleSchemas;
1094
1076
  return /* @__PURE__ */ jsxs("aside", { className: "flex flex-col h-full min-h-0 border-r bg-muted/10", children: [
1095
- /* @__PURE__ */ jsx(
1096
- BrandHeader,
1097
- {
1098
- info,
1099
- endpoints,
1100
- rawSchema,
1101
- resolvedBaseUrl
1102
- }
1103
- ),
1077
+ /* @__PURE__ */ jsx(BrandHeader, { info }),
1104
1078
  /* @__PURE__ */ jsx(
1105
1079
  Toolbar,
1106
1080
  {
@@ -1110,8 +1084,9 @@ function DocsSidebar({
1110
1084
  showSchemaSelector,
1111
1085
  search,
1112
1086
  onSearchChange: setSearch,
1113
- methodFilter,
1114
- onMethodFilterChange: setMethodFilter
1087
+ endpoints,
1088
+ rawSchema,
1089
+ resolvedBaseUrl
1115
1090
  }
1116
1091
  ),
1117
1092
  /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(SidebarBody, { body, onNavigate }) })
@@ -1210,21 +1185,14 @@ var useEndpointDocStore = create()(
1210
1185
  persist(
1211
1186
  (set) => ({
1212
1187
  ...initialState,
1213
- toggleSection: /* @__PURE__ */ __name((endpointId, sectionId) => set((state) => {
1188
+ toggleSection: /* @__PURE__ */ __name((endpointId, sectionId, defaultOpen) => set((state) => {
1214
1189
  const key = sectionKey(endpointId, sectionId);
1215
1190
  const current = state.openSections[key];
1191
+ const visible = current === void 0 ? defaultOpen : current;
1216
1192
  return {
1217
1193
  openSections: {
1218
1194
  ...state.openSections,
1219
- // If there's no explicit override yet, the user's
1220
- // first click means "flip from the default". We
1221
- // assume the default was ``true`` for the most
1222
- // common case (bodies/responses) and ``false``
1223
- // otherwise; the Section component tracks this
1224
- // via its ``defaultOpen`` prop and never calls
1225
- // toggle on sections whose defaults match the
1226
- // next state.
1227
- [key]: current === void 0 ? false : !current
1195
+ [key]: !visible
1228
1196
  }
1229
1197
  };
1230
1198
  }), "toggleSection"),
@@ -1383,15 +1351,15 @@ function IconButton({ label, onClick, children, active }) {
1383
1351
  ] });
1384
1352
  }
1385
1353
  __name(IconButton, "IconButton");
1386
- function MetaActions({ anchor, endpointMarkdown, presentSections }) {
1354
+ function MetaActions({ anchor, presentSections }) {
1387
1355
  const { endpointId } = useEndpointDocContext();
1388
1356
  const expandAll = useEndpointDocStore((s) => s.expandAll);
1389
1357
  const collapseAll = useEndpointDocStore((s) => s.collapseAll);
1390
1358
  const openSections = useEndpointDocStore((s) => s.openSections);
1391
- const [justCopied, setJustCopied] = useState(null);
1392
- const flash = useCallback((which) => {
1393
- setJustCopied(which);
1394
- setTimeout(() => setJustCopied(null), 1200);
1359
+ const [linkCopied, setLinkCopied] = useState(false);
1360
+ const flashLink = useCallback(() => {
1361
+ setLinkCopied(true);
1362
+ setTimeout(() => setLinkCopied(false), 1200);
1395
1363
  }, []);
1396
1364
  const mostlyOpen = useMemo(() => {
1397
1365
  if (presentSections.length === 0) return false;
@@ -1404,43 +1372,21 @@ function MetaActions({ anchor, endpointMarkdown, presentSections }) {
1404
1372
  const copyLink = useCallback(() => {
1405
1373
  if (typeof window === "undefined") return;
1406
1374
  const url = `${window.location.origin}${window.location.pathname}#${anchor}`;
1407
- void navigator.clipboard?.writeText(url).then(() => flash("link"));
1408
- }, [anchor, flash]);
1409
- const copyMarkdown = useCallback(() => {
1410
- if (typeof window === "undefined") return;
1411
- void navigator.clipboard?.writeText(endpointMarkdown).then(() => flash("md"));
1412
- }, [endpointMarkdown, flash]);
1375
+ void navigator.clipboard?.writeText(url).then(flashLink);
1376
+ }, [anchor, flashLink]);
1413
1377
  const toggleAll = useCallback(() => {
1414
1378
  if (mostlyOpen) collapseAll(endpointId, presentSections);
1415
1379
  else expandAll(endpointId, presentSections);
1416
1380
  }, [mostlyOpen, collapseAll, expandAll, endpointId, presentSections]);
1381
+ const linkLabel = linkCopied ? "Copied!" : "Copy link to endpoint";
1382
+ const linkIcon = linkCopied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" });
1383
+ const showToggleAll = presentSections.length >= 2;
1384
+ const toggleAllLabel = mostlyOpen ? "Collapse all sections" : "Expand all sections";
1385
+ const toggleAllIcon = mostlyOpen ? /* @__PURE__ */ jsx(ChevronsDownUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-3.5 w-3.5" });
1386
+ const toggleAllNode = showToggleAll ? /* @__PURE__ */ jsx(IconButton, { label: toggleAllLabel, onClick: toggleAll, children: toggleAllIcon }) : null;
1417
1387
  return /* @__PURE__ */ jsx(SafeTooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
1418
- /* @__PURE__ */ jsx(
1419
- IconButton,
1420
- {
1421
- label: justCopied === "link" ? "Copied!" : "Copy link to endpoint",
1422
- onClick: copyLink,
1423
- active: justCopied === "link",
1424
- children: justCopied === "link" ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" })
1425
- }
1426
- ),
1427
- /* @__PURE__ */ jsx(
1428
- IconButton,
1429
- {
1430
- label: justCopied === "md" ? "Copied!" : "Copy as Markdown (for AI)",
1431
- onClick: copyMarkdown,
1432
- active: justCopied === "md",
1433
- children: justCopied === "md" ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(FileCode2, { className: "h-3.5 w-3.5" })
1434
- }
1435
- ),
1436
- presentSections.length >= 2 && /* @__PURE__ */ jsx(
1437
- IconButton,
1438
- {
1439
- label: mostlyOpen ? "Collapse all sections" : "Expand all sections",
1440
- onClick: toggleAll,
1441
- children: mostlyOpen ? /* @__PURE__ */ jsx(ChevronsDownUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-3.5 w-3.5" })
1442
- }
1443
- )
1388
+ /* @__PURE__ */ jsx(IconButton, { label: linkLabel, onClick: copyLink, active: linkCopied, children: linkIcon }),
1389
+ toggleAllNode
1444
1390
  ] }) });
1445
1391
  }
1446
1392
  __name(MetaActions, "MetaActions");
@@ -1463,35 +1409,57 @@ function EndpointHeader({
1463
1409
  presentSections
1464
1410
  }) {
1465
1411
  const endpointMd = useMemo(() => endpointToMarkdown(endpoint), [endpoint]);
1412
+ const [aiCopied, setAiCopied] = useState(false);
1413
+ const onAiCopy = useCallback(() => {
1414
+ if (typeof window === "undefined") return;
1415
+ void navigator.clipboard?.writeText(endpointMd).then(() => {
1416
+ setAiCopied(true);
1417
+ setTimeout(() => setAiCopied(false), 1200);
1418
+ });
1419
+ }, [endpointMd]);
1420
+ const tryItLabel = isLoadedInPlayground ? "Loaded" : "Try it";
1421
+ const aiCopyIcon = aiCopied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" });
1422
+ const aiCopyLabel = aiCopied ? "Copied" : "AI Copy";
1423
+ const descriptionNode = endpoint.description ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: /* @__PURE__ */ jsx(MarkdownMessage, { content: endpoint.description }) }) : null;
1466
1424
  return /* @__PURE__ */ jsxs("header", { className: "space-y-3", children: [
1467
1425
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [
1468
1426
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
1469
1427
  /* @__PURE__ */ jsx(MethodBadge, { method: endpoint.method }),
1470
- /* @__PURE__ */ jsx(
1471
- MetaActions,
1428
+ /* @__PURE__ */ jsx(MetaActions, { anchor, presentSections })
1429
+ ] }),
1430
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
1431
+ /* @__PURE__ */ jsxs(
1432
+ Button,
1472
1433
  {
1473
- anchor,
1474
- endpointMarkdown: endpointMd,
1475
- presentSections
1434
+ size: "sm",
1435
+ variant: "secondary",
1436
+ onClick: onAiCopy,
1437
+ title: "Copy endpoint as Markdown for AI",
1438
+ "aria-label": "Copy endpoint as Markdown for AI",
1439
+ className: "h-7 text-xs gap-1.5 px-2.5",
1440
+ children: [
1441
+ aiCopyIcon,
1442
+ aiCopyLabel
1443
+ ]
1444
+ }
1445
+ ),
1446
+ /* @__PURE__ */ jsxs(
1447
+ Button,
1448
+ {
1449
+ size: "sm",
1450
+ variant: isLoadedInPlayground ? "secondary" : "default",
1451
+ onClick: onTryIt,
1452
+ className: "h-7 text-xs gap-1.5 px-2.5",
1453
+ children: [
1454
+ /* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }),
1455
+ tryItLabel
1456
+ ]
1476
1457
  }
1477
1458
  )
1478
- ] }),
1479
- /* @__PURE__ */ jsxs(
1480
- Button,
1481
- {
1482
- size: "sm",
1483
- variant: isLoadedInPlayground ? "secondary" : "default",
1484
- onClick: onTryIt,
1485
- className: "ml-auto h-7 text-xs gap-1.5 px-2.5",
1486
- children: [
1487
- /* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }),
1488
- isLoadedInPlayground ? "Loaded" : "Try it"
1489
- ]
1490
- }
1491
- )
1459
+ ] })
1492
1460
  ] }),
1493
1461
  /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx(PathDisplay, { path: endpoint.path }) }),
1494
- endpoint.description && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: /* @__PURE__ */ jsx(MarkdownMessage, { content: endpoint.description }) })
1462
+ descriptionNode
1495
1463
  ] });
1496
1464
  }
1497
1465
  __name(EndpointHeader, "EndpointHeader");
@@ -1924,7 +1892,7 @@ function Section({ id, title, badge, children }) {
1924
1892
  title,
1925
1893
  badge,
1926
1894
  open,
1927
- onToggle: () => toggleSection(endpointId, id)
1895
+ onToggle: () => toggleSection(endpointId, id, defaultOpen)
1928
1896
  }
1929
1897
  ),
1930
1898
  open && /* @__PURE__ */ jsx("div", { children })
@@ -3459,5 +3427,5 @@ var DocsLayout = /* @__PURE__ */ __name(() => {
3459
3427
  }, "DocsLayout");
3460
3428
 
3461
3429
  export { DocsLayout };
3462
- //# sourceMappingURL=DocsLayout-ESVQZO3V.mjs.map
3463
- //# sourceMappingURL=DocsLayout-ESVQZO3V.mjs.map
3430
+ //# sourceMappingURL=DocsLayout-CTJINVBM.mjs.map
3431
+ //# sourceMappingURL=DocsLayout-CTJINVBM.mjs.map