doccupine 0.0.47 → 0.0.48
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const docsSideBarTemplate = "\"use client\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Space } from \"cherry-styled-components/src/lib\";\nimport {\n StyledIndexSidebar,\n StyledIndexSidebarLink,\n StyledIndexSidebarLabel,\n} from \"@/components/layout/DocsComponents\";\n\nexport interface Heading {\n id: string;\n text: string;\n level: number;\n}\n\nexport function DocsSideBar({ headings }: { headings: Heading[] }) {\n const [activeId, setActiveId] = useState<string>(\"\");\n\n const handleScroll = useCallback(() => {\n if (headings.length === 0) return;\n\n const headingElements = headings\n .map((heading) => document.getElementById(heading.id))\n .filter(Boolean) as HTMLElement[];\n\n if (headingElements.length === 0) return;\n\n const windowHeight = window.innerHeight;\n\n const visibleHeadings = headingElements.filter((element) => {\n const rect = element.getBoundingClientRect();\n const elementTop = rect.top;\n const elementBottom = rect.bottom;\n return elementTop < windowHeight && elementBottom > -50;\n });\n\n if (visibleHeadings.length > 0) {\n let closestHeading = visibleHeadings[0];\n let closestDistance = Math.abs(\n closestHeading.getBoundingClientRect().top,\n );\n for (const heading of visibleHeadings) {\n const distance = Math.abs(heading.getBoundingClientRect().top);\n if (\n distance < closestDistance &&\n heading.getBoundingClientRect().top <= windowHeight * 0.3\n ) {\n closestDistance = distance;\n closestHeading = heading;\n }\n }\n setActiveId(closestHeading.id);\n return;\n }\n\n let currentActiveId = headings[0].id;\n for (const element of headingElements) {\n const rect = element.getBoundingClientRect();\n if (rect.top <=
|
|
1
|
+
export declare const docsSideBarTemplate = "\"use client\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Space } from \"cherry-styled-components/src/lib\";\nimport {\n StyledIndexSidebar,\n StyledIndexSidebarLink,\n StyledIndexSidebarLabel,\n} from \"@/components/layout/DocsComponents\";\n\nexport interface Heading {\n id: string;\n text: string;\n level: number;\n}\n\nexport function DocsSideBar({ headings }: { headings: Heading[] }) {\n const [activeId, setActiveId] = useState<string>(\"\");\n\n const getScrollOffset = useCallback(() => {\n return document.getElementById(\"static-links\") ? 90 : 18;\n }, []);\n\n const handleScroll = useCallback(() => {\n if (headings.length === 0) return;\n\n const offset = getScrollOffset();\n\n const headingElements = headings\n .map((heading) => document.getElementById(heading.id))\n .filter(Boolean) as HTMLElement[];\n\n if (headingElements.length === 0) return;\n\n const windowHeight = window.innerHeight;\n\n const visibleHeadings = headingElements.filter((element) => {\n const rect = element.getBoundingClientRect();\n const elementTop = rect.top;\n const elementBottom = rect.bottom;\n return elementTop < windowHeight && elementBottom > -50;\n });\n\n if (visibleHeadings.length > 0) {\n let closestHeading = visibleHeadings[0];\n let closestDistance = Math.abs(\n closestHeading.getBoundingClientRect().top - offset,\n );\n for (const heading of visibleHeadings) {\n const distance = Math.abs(heading.getBoundingClientRect().top - offset);\n if (\n distance < closestDistance &&\n heading.getBoundingClientRect().top <= windowHeight * 0.3\n ) {\n closestDistance = distance;\n closestHeading = heading;\n }\n }\n setActiveId(closestHeading.id);\n return;\n }\n\n let currentActiveId = headings[0].id;\n for (const element of headingElements) {\n const rect = element.getBoundingClientRect();\n if (rect.top <= offset) {\n currentActiveId = element.id;\n } else {\n break;\n }\n }\n setActiveId(currentActiveId);\n }, [headings, getScrollOffset]);\n\n useEffect(() => {\n if (headings.length === 0) return;\n // Run initial scroll check on next frame to avoid synchronous setState in effect\n const rafId = requestAnimationFrame(handleScroll);\n let timeoutId: NodeJS.Timeout;\n const throttledHandleScroll = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(handleScroll, 50);\n };\n window.addEventListener(\"scroll\", throttledHandleScroll);\n window.addEventListener(\"resize\", handleScroll);\n return () => {\n window.removeEventListener(\"scroll\", throttledHandleScroll);\n window.removeEventListener(\"resize\", handleScroll);\n cancelAnimationFrame(rafId);\n clearTimeout(timeoutId);\n };\n }, [handleScroll, headings]);\n\n const handleHeadingClick = (headingId: string) => {\n const element = document.getElementById(headingId);\n if (element) {\n const offset = getScrollOffset();\n const elementPosition =\n element.getBoundingClientRect().top + window.scrollY;\n window.scrollTo({ top: elementPosition - offset, behavior: \"smooth\" });\n }\n };\n\n return (\n <StyledIndexSidebar>\n {headings?.length > 0 && (\n <>\n <StyledIndexSidebarLabel>On this page</StyledIndexSidebarLabel>\n <Space $size={20} />\n </>\n )}\n {headings.map((heading, index) => (\n <li\n key={index}\n style={{ paddingLeft: `${(heading.level - 1) * 16}px` }}\n >\n <StyledIndexSidebarLink\n href={`#${heading.id}`}\n onClick={(e) => {\n e.preventDefault();\n handleHeadingClick(heading.id);\n }}\n $isActive={activeId === heading.id}\n >\n {heading.text}\n </StyledIndexSidebarLink>\n </li>\n ))}\n </StyledIndexSidebar>\n );\n}\n";
|
|
@@ -16,9 +16,15 @@ export interface Heading {
|
|
|
16
16
|
export function DocsSideBar({ headings }: { headings: Heading[] }) {
|
|
17
17
|
const [activeId, setActiveId] = useState<string>("");
|
|
18
18
|
|
|
19
|
+
const getScrollOffset = useCallback(() => {
|
|
20
|
+
return document.getElementById("static-links") ? 90 : 18;
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
19
23
|
const handleScroll = useCallback(() => {
|
|
20
24
|
if (headings.length === 0) return;
|
|
21
25
|
|
|
26
|
+
const offset = getScrollOffset();
|
|
27
|
+
|
|
22
28
|
const headingElements = headings
|
|
23
29
|
.map((heading) => document.getElementById(heading.id))
|
|
24
30
|
.filter(Boolean) as HTMLElement[];
|
|
@@ -37,10 +43,10 @@ export function DocsSideBar({ headings }: { headings: Heading[] }) {
|
|
|
37
43
|
if (visibleHeadings.length > 0) {
|
|
38
44
|
let closestHeading = visibleHeadings[0];
|
|
39
45
|
let closestDistance = Math.abs(
|
|
40
|
-
closestHeading.getBoundingClientRect().top,
|
|
46
|
+
closestHeading.getBoundingClientRect().top - offset,
|
|
41
47
|
);
|
|
42
48
|
for (const heading of visibleHeadings) {
|
|
43
|
-
const distance = Math.abs(heading.getBoundingClientRect().top);
|
|
49
|
+
const distance = Math.abs(heading.getBoundingClientRect().top - offset);
|
|
44
50
|
if (
|
|
45
51
|
distance < closestDistance &&
|
|
46
52
|
heading.getBoundingClientRect().top <= windowHeight * 0.3
|
|
@@ -56,14 +62,14 @@ export function DocsSideBar({ headings }: { headings: Heading[] }) {
|
|
|
56
62
|
let currentActiveId = headings[0].id;
|
|
57
63
|
for (const element of headingElements) {
|
|
58
64
|
const rect = element.getBoundingClientRect();
|
|
59
|
-
if (rect.top <=
|
|
65
|
+
if (rect.top <= offset) {
|
|
60
66
|
currentActiveId = element.id;
|
|
61
67
|
} else {
|
|
62
68
|
break;
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
setActiveId(currentActiveId);
|
|
66
|
-
}, [headings]);
|
|
72
|
+
}, [headings, getScrollOffset]);
|
|
67
73
|
|
|
68
74
|
useEffect(() => {
|
|
69
75
|
if (headings.length === 0) return;
|
|
@@ -87,7 +93,10 @@ export function DocsSideBar({ headings }: { headings: Heading[] }) {
|
|
|
87
93
|
const handleHeadingClick = (headingId: string) => {
|
|
88
94
|
const element = document.getElementById(headingId);
|
|
89
95
|
if (element) {
|
|
90
|
-
|
|
96
|
+
const offset = getScrollOffset();
|
|
97
|
+
const elementPosition =
|
|
98
|
+
element.getBoundingClientRect().top + window.scrollY;
|
|
99
|
+
window.scrollTo({ top: elementPosition - offset, behavior: "smooth" });
|
|
91
100
|
}
|
|
92
101
|
};
|
|
93
102
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const iconTemplate = "import { icons } from \"lucide-react\";\n\nexport type IconProps = keyof typeof icons;\n\ninterface Props {\n name: string | IconProps;\n color?: string;\n size?: number;\n className?: string;\n}\n\nfunction transformIconName(name: string): string {\n return name\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n\nconst Icon = ({ name, color, size, className }: Props) => {\n const IconName = transformIconName(name as string);\n const LucideIcon = icons[IconName as keyof typeof icons];\n\n return <LucideIcon color={color} size={size} className={className} />;\n};\n\nexport { Icon };\n";
|
|
1
|
+
export declare const iconTemplate = "import { icons } from \"lucide-react\";\n\nexport type IconProps = keyof typeof icons;\n\ninterface Props {\n name: string | IconProps;\n color?: string;\n size?: number;\n className?: string;\n}\n\nfunction transformIconName(name: string): string {\n return name\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n\nconst Icon = ({ name, color, size, className }: Props) => {\n const IconName = transformIconName(name as string);\n const LucideIcon = icons[IconName as keyof typeof icons];\n if (!LucideIcon) return null;\n\n return <LucideIcon color={color} size={size} className={className} />;\n};\n\nexport { Icon };\n";
|
|
@@ -19,6 +19,7 @@ function transformIconName(name: string): string {
|
|
|
19
19
|
const Icon = ({ name, color, size, className }: Props) => {
|
|
20
20
|
const IconName = transformIconName(name as string);
|
|
21
21
|
const LucideIcon = icons[IconName as keyof typeof icons];
|
|
22
|
+
if (!LucideIcon) return null;
|
|
22
23
|
|
|
23
24
|
return <LucideIcon color={color} size={size} className={className} />;
|
|
24
25
|
};
|
package/package.json
CHANGED