doccupine 0.0.8 → 0.0.9
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/index.js
CHANGED
|
@@ -469,7 +469,7 @@ export default function Home() {
|
|
|
469
469
|
program
|
|
470
470
|
.name("doccupine")
|
|
471
471
|
.description("Watch MDX files and generate Next.js documentation pages automatically")
|
|
472
|
-
.version("0.0.
|
|
472
|
+
.version("0.0.9");
|
|
473
473
|
program
|
|
474
474
|
.command("watch", { isDefault: true })
|
|
475
475
|
.description("Watch a directory for MDX changes and generate Next.js app")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const docsTemplate = "\"use client\";\nimport { useEffect, useState } from \"react\";\nimport { Flex, Space } from \"cherry-styled-components/src/lib\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { Code } from \"@/components/layout/Code\";\nimport { \n DocsContainer,\n StyledMarkdownContainer,\n StyledIndexSidebar,\n} from \"@/components/layout/DocsComponents\";\
|
|
1
|
+
export declare const docsTemplate = "\"use client\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport { Flex, Space } from \"cherry-styled-components/src/lib\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { Code } from \"@/components/layout/Code\";\nimport { \n DocsContainer,\n StyledMarkdownContainer,\n StyledIndexSidebar,\n StyledIndexSidebarLink,\n StyledIndexSidebarLabel,\n} from \"@/components/layout/DocsComponents\";\n\ninterface DocsProps {\n content: string;\n}\n\n\ninterface Heading {\n id: string;\n text: string;\n level: number;\n}\n\nfunction generateId(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .trim();\n}\n\nfunction extractHeadings(content: string): Heading[] {\n const headingRegex = /^(#{1,6})\\s+(.+)$/gm;\n const headings: Heading[] = [];\n let match;\n\n while ((match = headingRegex.exec(content)) !== null) {\n const level = match[1].length;\n const text = match[2].trim();\n const id = generateId(text);\n headings.push({ id, text, level });\n }\n\n return headings;\n}\n\nfunction useActiveHeading(headings: Heading[]): string {\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);\n\n if (headingElements.length === 0) return;\n\n const windowHeight = window.innerHeight;\n\n const visibleHeadings = headingElements.filter((element) => {\n if (!element) return false;\n\n const rect = element.getBoundingClientRect();\n const elementTop = rect.top;\n const elementBottom = rect.bottom;\n\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\n for (const heading of visibleHeadings) {\n if (!heading) continue;\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\n setActiveId(closestHeading!.id);\n return;\n }\n\n let currentActiveId = headings[0].id;\n\n for (const element of headingElements) {\n if (!element) continue;\n\n const rect = element.getBoundingClientRect();\n if (rect.top <= 0) {\n currentActiveId = element.id;\n } else {\n break;\n }\n }\n\n setActiveId(currentActiveId);\n }, [headings]);\n\n useEffect(() => {\n if (headings.length === 0) return;\n\n handleScroll();\n\n let timeoutId: NodeJS.Timeout;\n const throttledHandleScroll = () => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(handleScroll, 50);\n };\n\n window.addEventListener(\"scroll\", throttledHandleScroll);\n window.addEventListener(\"resize\", handleScroll);\n\n return () => {\n window.removeEventListener(\"scroll\", throttledHandleScroll);\n window.removeEventListener(\"resize\", handleScroll);\n clearTimeout(timeoutId);\n };\n }, [handleScroll, headings]);\n\n return activeId;\n}\n \nfunction Docs({ content }: DocsProps) {\n const [headings, setHeadings] = useState<Heading[]>([]);\n const activeHeadingId = useActiveHeading(headings);\n\n useEffect(() => {\n if (content) {\n const extractedHeadings = extractHeadings(content);\n setHeadings(extractedHeadings);\n }\n }, [content]);\n\n const handleHeadingClick = (headingId: string) => {\n const element = document.getElementById(headingId);\n if (element) {\n element.scrollIntoView({\n behavior: \"smooth\",\n block: \"start\",\n });\n }\n };\n\n return (\n <>\n <DocsContainer>\n <Flex $gap={20}>\n <StyledMarkdownContainer>\n {content && (\n <Markdown\n remarkPlugins={[remarkGfm]}\n components={{\n code(props) {\n const { children, className, node, ...rest } = props;\n const match = /language-(\\w+)/.exec(className || \"\");\n return match ? (\n <Code\n {...rest}\n className={className}\n code={String(children).replace(/\\n$/, \"\")}\n language={match[1]}\n />\n ) : (\n <code {...rest} className={className}>\n {children}\n </code>\n );\n },\n h1: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h1 id={id} {...props}>\n {children}\n </h1>\n );\n },\n h2: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h2 id={id} {...props}>\n {children}\n </h2>\n );\n },\n h3: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h3 id={id} {...props}>\n {children}\n </h3>\n );\n },\n h4: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h4 id={id} {...props}>\n {children}\n </h4>\n );\n },\n h5: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h5 id={id} {...props}>\n {children}\n </h5>\n );\n },\n h6: ({ children, ...props }) => {\n const id = generateId(String(children));\n return (\n <h6 id={id} {...props}>\n {children}\n </h6>\n );\n },\n }}\n >\n {content}\n </Markdown>\n )}\n </StyledMarkdownContainer>\n </Flex>\n </DocsContainer>\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={{\n paddingLeft: `${(heading.level - 1) * 16}px`,\n }}\n >\n <StyledIndexSidebarLink\n href={`#${heading.id}`}\n onClick={(e) => {\n e.preventDefault();\n handleHeadingClick(heading.id);\n }}\n $isActive={activeHeadingId === heading.id}\n >\n {heading.text}\n </StyledIndexSidebarLink>\n </li>\n ))}\n </StyledIndexSidebar>\n </>\n );\n}\n\nexport { Docs };\n";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const docsTemplate = `"use client";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useEffect, useState, useCallback } from "react";
|
|
3
3
|
import { Flex, Space } from "cherry-styled-components/src/lib";
|
|
4
4
|
import Markdown from "react-markdown";
|
|
5
5
|
import remarkGfm from "remark-gfm";
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
DocsContainer,
|
|
9
9
|
StyledMarkdownContainer,
|
|
10
10
|
StyledIndexSidebar,
|
|
11
|
+
StyledIndexSidebarLink,
|
|
12
|
+
StyledIndexSidebarLabel,
|
|
11
13
|
} from "@/components/layout/DocsComponents";
|
|
12
|
-
import { StyledText } from "@/components/layout/Typography";
|
|
13
14
|
|
|
14
15
|
interface DocsProps {
|
|
15
16
|
content: string;
|
|
@@ -44,9 +45,96 @@ function extractHeadings(content: string): Heading[] {
|
|
|
44
45
|
|
|
45
46
|
return headings;
|
|
46
47
|
}
|
|
48
|
+
|
|
49
|
+
function useActiveHeading(headings: Heading[]): string {
|
|
50
|
+
const [activeId, setActiveId] = useState<string>("");
|
|
51
|
+
|
|
52
|
+
const handleScroll = useCallback(() => {
|
|
53
|
+
if (headings.length === 0) return;
|
|
54
|
+
|
|
55
|
+
const headingElements = headings
|
|
56
|
+
.map((heading) => document.getElementById(heading.id))
|
|
57
|
+
.filter(Boolean);
|
|
58
|
+
|
|
59
|
+
if (headingElements.length === 0) return;
|
|
60
|
+
|
|
61
|
+
const windowHeight = window.innerHeight;
|
|
62
|
+
|
|
63
|
+
const visibleHeadings = headingElements.filter((element) => {
|
|
64
|
+
if (!element) return false;
|
|
65
|
+
|
|
66
|
+
const rect = element.getBoundingClientRect();
|
|
67
|
+
const elementTop = rect.top;
|
|
68
|
+
const elementBottom = rect.bottom;
|
|
69
|
+
|
|
70
|
+
return elementTop < windowHeight && elementBottom > -50;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (visibleHeadings.length > 0) {
|
|
74
|
+
let closestHeading = visibleHeadings[0];
|
|
75
|
+
let closestDistance = Math.abs(
|
|
76
|
+
closestHeading!.getBoundingClientRect().top,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
for (const heading of visibleHeadings) {
|
|
80
|
+
if (!heading) continue;
|
|
81
|
+
const distance = Math.abs(heading.getBoundingClientRect().top);
|
|
82
|
+
if (
|
|
83
|
+
distance < closestDistance &&
|
|
84
|
+
heading.getBoundingClientRect().top <= windowHeight * 0.3
|
|
85
|
+
) {
|
|
86
|
+
closestDistance = distance;
|
|
87
|
+
closestHeading = heading;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setActiveId(closestHeading!.id);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let currentActiveId = headings[0].id;
|
|
96
|
+
|
|
97
|
+
for (const element of headingElements) {
|
|
98
|
+
if (!element) continue;
|
|
99
|
+
|
|
100
|
+
const rect = element.getBoundingClientRect();
|
|
101
|
+
if (rect.top <= 0) {
|
|
102
|
+
currentActiveId = element.id;
|
|
103
|
+
} else {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
setActiveId(currentActiveId);
|
|
109
|
+
}, [headings]);
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (headings.length === 0) return;
|
|
113
|
+
|
|
114
|
+
handleScroll();
|
|
115
|
+
|
|
116
|
+
let timeoutId: NodeJS.Timeout;
|
|
117
|
+
const throttledHandleScroll = () => {
|
|
118
|
+
clearTimeout(timeoutId);
|
|
119
|
+
timeoutId = setTimeout(handleScroll, 50);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
window.addEventListener("scroll", throttledHandleScroll);
|
|
123
|
+
window.addEventListener("resize", handleScroll);
|
|
124
|
+
|
|
125
|
+
return () => {
|
|
126
|
+
window.removeEventListener("scroll", throttledHandleScroll);
|
|
127
|
+
window.removeEventListener("resize", handleScroll);
|
|
128
|
+
clearTimeout(timeoutId);
|
|
129
|
+
};
|
|
130
|
+
}, [handleScroll, headings]);
|
|
131
|
+
|
|
132
|
+
return activeId;
|
|
133
|
+
}
|
|
47
134
|
|
|
48
135
|
function Docs({ content }: DocsProps) {
|
|
49
136
|
const [headings, setHeadings] = useState<Heading[]>([]);
|
|
137
|
+
const activeHeadingId = useActiveHeading(headings);
|
|
50
138
|
|
|
51
139
|
useEffect(() => {
|
|
52
140
|
if (content) {
|
|
@@ -55,6 +143,16 @@ function Docs({ content }: DocsProps) {
|
|
|
55
143
|
}
|
|
56
144
|
}, [content]);
|
|
57
145
|
|
|
146
|
+
const handleHeadingClick = (headingId: string) => {
|
|
147
|
+
const element = document.getElementById(headingId);
|
|
148
|
+
if (element) {
|
|
149
|
+
element.scrollIntoView({
|
|
150
|
+
behavior: "smooth",
|
|
151
|
+
block: "start",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
58
156
|
return (
|
|
59
157
|
<>
|
|
60
158
|
<DocsContainer>
|
|
@@ -139,20 +237,27 @@ function Docs({ content }: DocsProps) {
|
|
|
139
237
|
<StyledIndexSidebar>
|
|
140
238
|
{headings?.length > 0 && (
|
|
141
239
|
<>
|
|
142
|
-
<
|
|
240
|
+
<StyledIndexSidebarLabel>On this page</StyledIndexSidebarLabel>
|
|
143
241
|
<Space $size={20} />
|
|
144
242
|
</>
|
|
145
243
|
)}
|
|
146
244
|
{headings.map((heading, index) => (
|
|
147
245
|
<li
|
|
148
246
|
key={index}
|
|
149
|
-
style={
|
|
150
|
-
{
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
}
|
|
247
|
+
style={{
|
|
248
|
+
paddingLeft: \`\${(heading.level - 1) * 16}px\`,
|
|
249
|
+
}}
|
|
154
250
|
>
|
|
155
|
-
<
|
|
251
|
+
<StyledIndexSidebarLink
|
|
252
|
+
href={\`#\${heading.id}\`}
|
|
253
|
+
onClick={(e) => {
|
|
254
|
+
e.preventDefault();
|
|
255
|
+
handleHeadingClick(heading.id);
|
|
256
|
+
}}
|
|
257
|
+
$isActive={activeHeadingId === heading.id}
|
|
258
|
+
>
|
|
259
|
+
{heading.text}
|
|
260
|
+
</StyledIndexSidebarLink>
|
|
156
261
|
</li>
|
|
157
262
|
))}
|
|
158
263
|
</StyledIndexSidebar>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const docsComponentsTemplate = "\"use client\";\nimport { mq, Theme } from \"@/app/theme\";\nimport {\n resetButton,\n styledStrong,\n styledText,\n} from \"cherry-styled-components/src/lib\";\nimport Link from \"next/link\";\nimport { rgba } from \"polished\";\nimport React from \"react\";\nimport styled, { css } from \"styled-components\";\nimport { interactiveStyles } from \"./SharedStyled\";\n\ninterface DocsProps {\n children: React.ReactNode;\n}\n\nconst StyledDocsWrapper = styled.div<{ theme: Theme }>`\n position: relative;\n`;\n\nconst StyledDocsSidebar = styled.div<{ theme: Theme }>`\n clear: both;\n`;\n\nconst StyledDocsContainer = styled.div<{ theme: Theme }>`\n position: relative;\n padding: 0;\n width: 100%;\n ${({ theme }) => styledText(theme)};\n\n ${mq(\"lg\")} {\n padding-left: 320px;\n padding-right: 320px;\n }\n\n & p {\n color: ${({ theme }) => theme.colors.grayDark};\n }\n\n & pre {\n max-width: 100%;\n }\n\n & ul {\n list-style: none;\n padding: 0;\n margin: 0;\n\n & li {\n text-indent: 0;\n display: block;\n position: relative;\n padding: 0 0 0 15px;\n margin: 0;\n ${({ theme }) => styledText(theme)};\n min-height: 23px;\n\n $mq: \"lg\" {\n min-height: 27px;\n }\n\n &::before {\n content: \"\";\n display: block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: ${({ theme }) => theme.colors.primary};\n position: absolute;\n top: 8px;\n left: 2px;\n\n ${mq(\"lg\")} {\n top: 10px;\n }\n }\n }\n }\n\n & ol {\n padding: 0;\n margin: 0;\n\n & > li {\n position: relative;\n padding: 0;\n counter-increment: item;\n margin: 0;\n ${({ theme }) => styledText(theme)};\n\n &::before {\n content: counter(item) \".\";\n display: inline-block;\n margin: 0 4px 0 0;\n font-weight: 700;\n color: ${({ theme }) => theme.colors.primary};\n min-width: max-content;\n }\n }\n }\n`;\n\nexport const StyledMarkdownContainer = styled.div`\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex-wrap: wrap;\n flex: 1;\n max-width: 640px;\n margin: auto;\n\n ${mq(\"lg\")} {\n padding-bottom: 110px;\n }\n`;\n\ninterface Props {\n theme?: Theme;\n $isActive?: boolean;\n}\n\nexport const StyledSidebar = styled.nav<Props>`\n position: fixed;\n overflow-y: auto;\n max-height: calc(100svh - 70px);\n width: 100%;\n z-index: 99;\n top: 70px;\n height: 100%;\n padding: 20px;\n opacity: 0;\n pointer-events: none;\n transition: all 0.3s ease;\n transform: translateY(30px);\n left: 0;\n background: ${({ theme }) => theme.colors.light};\n\n ${mq(\"lg\")} {\n max-height: 100svh;\n width: 220px;\n background: transparent;\n padding: 90px 40px 40px;\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n background: ${({ theme }) => rgba(theme.colors.primaryLight, 0.1)};\n top: 0;\n width: 320px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n transform: translateY(0);\n opacity: 1;\n pointer-events: all;\n `}\n`;\n\nexport const StyledIndexSidebar = styled.ul<{ theme: Theme }>`\n display: none;\n list-style: none;\n margin: 0;\n padding: 0;\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100vh;\n overflow-y: auto;\n z-index: 1;\n padding: 40px;\n background: ${({ theme }) => theme.colors.light};\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n ${mq(\"lg\")} {\n display: block;\n }\n\n & li {\n padding: 5px 0;\n\n & a {\n ${({ theme }) => styledText(theme)};\n color: ${({ theme }) => theme.colors.primary};\n font-weight: 600;\n text-decoration: none;\n transition: all 0.3s ease;\n\n &:hover {\n color: ${({ theme }) => theme.colors.primaryDark};\n }\n }\n }\n`;\n\nexport const StyledSidebarList = styled.ul`\n list-style: none;\n margin: 0;\n padding: 0;\n`;\n\nexport const StyledStrong = styled.strong<{ theme: Theme }>`\n font-weight: 600;\n ${({ theme }) => styledStrong(theme)};\n`;\n\nexport const StyledSidebarListItem = styled.li`\n display: flex;\n gap: 10px;\n clear: both;\n`;\n\nexport const StyledSidebarListItemLink = styled(Link)<Props>`\n text-decoration: none;\n font-size: ${({ theme }) => theme.fontSizes.strong.xs};\n line-height: 1.6;\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.grayDark : theme.colors.primary};\n padding: 5px 0 5px 20px;\n display: flex;\n transition: all 0.3s ease;\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n ${mq(\"lg\")} {\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n }\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};\n border-color: ${({ theme }) => theme.colors.info};\n }\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n `\n\t\t\tcolor: ${theme.colors.dark};\n\t\t\tborder-color: ${theme.colors.info};\n\t\t\tfont-weight: 600;\n\t`};\n`;\n\nexport const StyleMobileBar = styled.button<Props>`\n ${resetButton};\n position: fixed;\n z-index: 1000;\n bottom: 0;\n right: 20px;\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n line-height: ${({ theme }) => theme.fontSizes.strong.lg};\n box-shadow: ${({ theme }) => theme.shadows.sm};\n background: ${({ theme }) =>\n theme.isDark\n ? rgba(theme.colors.grayLight, 0.7)\n : rgba(theme.colors.light, 0.7)};\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.dark : theme.colors.primary};\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n padding: 30px;\n border-radius: 100px;\n margin: 0 0 20px 0;\n font-weight: 600;\n display: flex;\n justify-content: flex-start;\n width: auto;\n\n ${mq(\"lg\")} {\n display: none;\n }\n\n ${({ $isActive }) => $isActive && `position: fixed; `};\n`;\n\nexport const StyledMobileBurger = styled.span<Props>`\n display: block;\n margin: auto 0;\n width: 18px;\n height: 18px;\n position: relative;\n overflow: hidden;\n background: transparent;\n position: relative;\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n width: 18px;\n height: 3px;\n border-radius: 3px;\n background: ${({ theme }) =>\n theme.isDark ? theme.colors.dark : theme.colors.primary};\n transition: all 0.3s ease;\n }\n\n &::before {\n top: 3px;\n }\n\n &::after {\n bottom: 3px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n &::before {\n transform: translateY(5px) rotate(45deg);\n }\n\n &::after {\n transform: translateY(-4px) rotate(-45deg);\n }\n `};\n`;\n\nexport const StyledInlineButton = styled.button<{ theme: Theme }>`\n ${resetButton};\n ${interactiveStyles};\n color: ${({ theme }) => theme.colors.primary};\n vertical-align: middle;\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n padding: 0;\n width: 18px;\n height: 18px;\n display: flex;\n margin: auto 0;\n transition: all 0.3s ease;\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) => theme.colors.light};\n background: ${({ theme }) => theme.colors.primary};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n\n & svg {\n vertical-align: middle;\n width: 12px;\n height: 12px;\n margin: auto;\n }\n`;\n\nexport const StyledPlusButton = styled.button<{ theme: Theme }>`\n ${resetButton};\n color: ${({ theme }) => theme.colors.primary};\n vertical-align: middle;\n padding: 0;\n width: 100%;\n height: 18px;\n display: flex;\n margin: auto 0;\n transition: all 0.3s ease;\n position: relative;\n margin: 20px 0 0 0;\n\n &::before {\n content: \"\";\n display: block;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 100%;\n height: 1px;\n border-radius: 3px;\n background: ${({ theme }) => theme.colors.grayLight};\n transition: all 0.3s ease;\n z-index: -1;\n }\n\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 18px;\n height: 18px;\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n background: ${({ theme }) => theme.colors.light};\n transition: all 0.3s ease;\n z-index: -1;\n }\n\n box-shadow: 0 0 0 0px ${({ theme }) => theme.colors.primary};\n\n @media (hover: hover) {\n &:hover {\n &::after {\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n }\n\n &:focus {\n &::after {\n border-color: ${({ theme }) => theme.colors.primary};\n box-shadow: 0 0 0 4px ${({ theme }) => theme.colors.primaryLight};\n }\n }\n\n &:active {\n &::after {\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n }\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) => theme.colors.light};\n\n &::after {\n background: ${({ theme }) => theme.colors.primary};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n }\n\n & svg {\n vertical-align: middle;\n width: 14px;\n height: 14px;\n margin: auto;\n }\n`;\n\nexport const StyledFullHeightInput = styled.div`\n height: 100%;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex: 1;\n\n & > span {\n height: 100%;\n width: 100%;\n }\n\n & textarea {\n height: 100%;\n }\n`;\n\nexport const StyledEditorWrapper = styled.div`\n flex: 1;\n\n &:empty {\n display: none;\n }\n`;\n\nfunction DocsWrapper({ children }: DocsProps) {\n return <StyledDocsWrapper>{children}</StyledDocsWrapper>;\n}\n\nfunction DocsSidebar({ children }: DocsProps) {\n return <StyledDocsSidebar>{children}</StyledDocsSidebar>;\n}\n\nfunction DocsContainer({ children }: DocsProps) {\n return <StyledDocsContainer>{children}</StyledDocsContainer>;\n}\n\nexport { DocsWrapper, DocsSidebar, DocsContainer };\n";
|
|
1
|
+
export declare const docsComponentsTemplate = "\"use client\";\nimport { mq, Theme } from \"@/app/theme\";\nimport {\n resetButton,\n styledSmall,\n styledStrong,\n styledText,\n} from \"cherry-styled-components/src/lib\";\nimport Link from \"next/link\";\nimport { rgba } from \"polished\";\nimport React from \"react\";\nimport styled, { css } from \"styled-components\";\nimport { interactiveStyles } from \"./SharedStyled\";\n\ninterface DocsProps {\n children: React.ReactNode;\n}\n\nconst StyledDocsWrapper = styled.div<{ theme: Theme }>`\n position: relative;\n`;\n\nconst StyledDocsSidebar = styled.div<{ theme: Theme }>`\n clear: both;\n`;\n\nconst StyledDocsContainer = styled.div<{ theme: Theme }>`\n position: relative;\n padding: 0;\n width: 100%;\n ${({ theme }) => styledText(theme)};\n\n ${mq(\"lg\")} {\n padding-left: 320px;\n padding-right: 320px;\n }\n\n & p {\n color: ${({ theme }) => theme.colors.grayDark};\n }\n\n & pre {\n max-width: 100%;\n }\n\n & ul {\n list-style: none;\n padding: 0;\n margin: 0;\n\n & li {\n text-indent: 0;\n display: block;\n position: relative;\n padding: 0 0 0 15px;\n margin: 0;\n ${({ theme }) => styledText(theme)};\n min-height: 23px;\n\n $mq: \"lg\" {\n min-height: 27px;\n }\n\n &::before {\n content: \"\";\n display: block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: ${({ theme }) => theme.colors.primary};\n position: absolute;\n top: 8px;\n left: 2px;\n\n ${mq(\"lg\")} {\n top: 10px;\n }\n }\n }\n }\n\n & ol {\n padding: 0;\n margin: 0;\n\n & > li {\n position: relative;\n padding: 0;\n counter-increment: item;\n margin: 0;\n ${({ theme }) => styledText(theme)};\n\n &::before {\n content: counter(item) \".\";\n display: inline-block;\n margin: 0 4px 0 0;\n font-weight: 700;\n color: ${({ theme }) => theme.colors.primary};\n min-width: max-content;\n }\n }\n }\n`;\n\nexport const StyledMarkdownContainer = styled.div`\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex-wrap: wrap;\n flex: 1;\n max-width: 640px;\n margin: auto;\n\n ${mq(\"lg\")} {\n padding-bottom: 110px;\n }\n`;\n\ninterface Props {\n theme?: Theme;\n $isActive?: boolean;\n}\n\nexport const StyledSidebar = styled.nav<Props>`\n position: fixed;\n overflow-y: auto;\n max-height: calc(100svh - 70px);\n width: 100%;\n z-index: 99;\n top: 70px;\n height: 100%;\n padding: 20px;\n opacity: 0;\n pointer-events: none;\n transition: all 0.3s ease;\n transform: translateY(30px);\n left: 0;\n background: ${({ theme }) => theme.colors.light};\n\n ${mq(\"lg\")} {\n max-height: 100svh;\n width: 220px;\n background: transparent;\n padding: 90px 40px 40px;\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n background: ${({ theme }) => rgba(theme.colors.primaryLight, 0.1)};\n top: 0;\n width: 320px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n transform: translateY(0);\n opacity: 1;\n pointer-events: all;\n `}\n`;\n\nexport const StyledIndexSidebar = styled.ul<{ theme: Theme }>`\n display: none;\n list-style: none;\n margin: 0;\n padding: 0;\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100vh;\n overflow-y: auto;\n z-index: 1;\n padding: 40px;\n background: ${({ theme }) => theme.colors.light};\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n ${mq(\"lg\")} {\n display: block;\n }\n\n & li {\n padding: 5px 0;\n }\n`;\n\nexport const StyledIndexSidebarLabel = styled.span<{ theme: Theme }>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme }) => theme.colors.grayDark};\n`;\n\nexport const StyledIndexSidebarLink = styled.a<{\n theme: Theme;\n $isActive: boolean;\n}>`\n ${({ theme }) => styledText(theme)};\n color: ${({ theme, $isActive }) =>\n $isActive ? theme.colors.primary : theme.colors.dark};\n font-weight: ${({ $isActive }) => ($isActive ? \"600\" : \"400\")};\n text-decoration: none;\n transition: all 0.3s ease;\n\n &:hover {\n color: ${({ theme }) => theme.colors.primaryDark};\n }\n`;\n\nexport const StyledSidebarList = styled.ul`\n list-style: none;\n margin: 0;\n padding: 0;\n`;\n\nexport const StyledStrong = styled.strong<{ theme: Theme }>`\n font-weight: 600;\n ${({ theme }) => styledStrong(theme)};\n`;\n\nexport const StyledSidebarListItem = styled.li`\n display: flex;\n gap: 10px;\n clear: both;\n`;\n\nexport const StyledSidebarListItemLink = styled(Link)<Props>`\n text-decoration: none;\n font-size: ${({ theme }) => theme.fontSizes.strong.xs};\n line-height: 1.6;\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.grayDark : theme.colors.primary};\n padding: 5px 0 5px 20px;\n display: flex;\n transition: all 0.3s ease;\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n ${mq(\"lg\")} {\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n }\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};\n border-color: ${({ theme }) => theme.colors.info};\n }\n }\n\n ${({ $isActive, theme }) =>\n $isActive &&\n `\n\t\t\tcolor: ${theme.colors.dark};\n\t\t\tborder-color: ${theme.colors.info};\n\t\t\tfont-weight: 600;\n\t`};\n`;\n\nexport const StyleMobileBar = styled.button<Props>`\n ${resetButton};\n position: fixed;\n z-index: 1000;\n bottom: 0;\n right: 20px;\n font-size: ${({ theme }) => theme.fontSizes.strong.lg};\n line-height: ${({ theme }) => theme.fontSizes.strong.lg};\n box-shadow: ${({ theme }) => theme.shadows.sm};\n background: ${({ theme }) =>\n theme.isDark\n ? rgba(theme.colors.grayLight, 0.7)\n : rgba(theme.colors.light, 0.7)};\n color: ${({ theme }) =>\n theme.isDark ? theme.colors.dark : theme.colors.primary};\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n padding: 30px;\n border-radius: 100px;\n margin: 0 0 20px 0;\n font-weight: 600;\n display: flex;\n justify-content: flex-start;\n width: auto;\n\n ${mq(\"lg\")} {\n display: none;\n }\n\n ${({ $isActive }) => $isActive && `position: fixed; `};\n`;\n\nexport const StyledMobileBurger = styled.span<Props>`\n display: block;\n margin: auto 0;\n width: 18px;\n height: 18px;\n position: relative;\n overflow: hidden;\n background: transparent;\n position: relative;\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n width: 18px;\n height: 3px;\n border-radius: 3px;\n background: ${({ theme }) =>\n theme.isDark ? theme.colors.dark : theme.colors.primary};\n transition: all 0.3s ease;\n }\n\n &::before {\n top: 3px;\n }\n\n &::after {\n bottom: 3px;\n }\n\n ${({ $isActive }) =>\n $isActive &&\n css`\n &::before {\n transform: translateY(5px) rotate(45deg);\n }\n\n &::after {\n transform: translateY(-4px) rotate(-45deg);\n }\n `};\n`;\n\nexport const StyledInlineButton = styled.button<{ theme: Theme }>`\n ${resetButton};\n ${interactiveStyles};\n color: ${({ theme }) => theme.colors.primary};\n vertical-align: middle;\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n padding: 0;\n width: 18px;\n height: 18px;\n display: flex;\n margin: auto 0;\n transition: all 0.3s ease;\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) => theme.colors.light};\n background: ${({ theme }) => theme.colors.primary};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n\n & svg {\n vertical-align: middle;\n width: 12px;\n height: 12px;\n margin: auto;\n }\n`;\n\nexport const StyledPlusButton = styled.button<{ theme: Theme }>`\n ${resetButton};\n color: ${({ theme }) => theme.colors.primary};\n vertical-align: middle;\n padding: 0;\n width: 100%;\n height: 18px;\n display: flex;\n margin: auto 0;\n transition: all 0.3s ease;\n position: relative;\n margin: 20px 0 0 0;\n\n &::before {\n content: \"\";\n display: block;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 100%;\n height: 1px;\n border-radius: 3px;\n background: ${({ theme }) => theme.colors.grayLight};\n transition: all 0.3s ease;\n z-index: -1;\n }\n\n &::after {\n content: \"\";\n display: block;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 18px;\n height: 18px;\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n background: ${({ theme }) => theme.colors.light};\n transition: all 0.3s ease;\n z-index: -1;\n }\n\n box-shadow: 0 0 0 0px ${({ theme }) => theme.colors.primary};\n\n @media (hover: hover) {\n &:hover {\n &::after {\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n }\n\n &:focus {\n &::after {\n border-color: ${({ theme }) => theme.colors.primary};\n box-shadow: 0 0 0 4px ${({ theme }) => theme.colors.primaryLight};\n }\n }\n\n &:active {\n &::after {\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n }\n\n @media (hover: hover) {\n &:hover {\n color: ${({ theme }) => theme.colors.light};\n\n &::after {\n background: ${({ theme }) => theme.colors.primary};\n border-color: ${({ theme }) => theme.colors.primary};\n }\n }\n }\n\n & svg {\n vertical-align: middle;\n width: 14px;\n height: 14px;\n margin: auto;\n }\n`;\n\nexport const StyledFullHeightInput = styled.div`\n height: 100%;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex: 1;\n\n & > span {\n height: 100%;\n width: 100%;\n }\n\n & textarea {\n height: 100%;\n }\n`;\n\nexport const StyledEditorWrapper = styled.div`\n flex: 1;\n\n &:empty {\n display: none;\n }\n`;\n\nfunction DocsWrapper({ children }: DocsProps) {\n return <StyledDocsWrapper>{children}</StyledDocsWrapper>;\n}\n\nfunction DocsSidebar({ children }: DocsProps) {\n return <StyledDocsSidebar>{children}</StyledDocsSidebar>;\n}\n\nfunction DocsContainer({ children }: DocsProps) {\n return <StyledDocsContainer>{children}</StyledDocsContainer>;\n}\n\nexport { DocsWrapper, DocsSidebar, DocsContainer };\n";
|
|
@@ -2,6 +2,7 @@ export const docsComponentsTemplate = `"use client";
|
|
|
2
2
|
import { mq, Theme } from "@/app/theme";
|
|
3
3
|
import {
|
|
4
4
|
resetButton,
|
|
5
|
+
styledSmall,
|
|
5
6
|
styledStrong,
|
|
6
7
|
styledText,
|
|
7
8
|
} from "cherry-styled-components/src/lib";
|
|
@@ -180,18 +181,27 @@ export const StyledIndexSidebar = styled.ul<{ theme: Theme }>\`
|
|
|
180
181
|
|
|
181
182
|
& li {
|
|
182
183
|
padding: 5px 0;
|
|
184
|
+
}
|
|
185
|
+
\`;
|
|
183
186
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
text-decoration: none;
|
|
189
|
-
transition: all 0.3s ease;
|
|
187
|
+
export const StyledIndexSidebarLabel = styled.span<{ theme: Theme }>\`
|
|
188
|
+
\${({ theme }) => styledSmall(theme)};
|
|
189
|
+
color: \${({ theme }) => theme.colors.grayDark};
|
|
190
|
+
\`;
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
export const StyledIndexSidebarLink = styled.a<{
|
|
193
|
+
theme: Theme;
|
|
194
|
+
$isActive: boolean;
|
|
195
|
+
}>\`
|
|
196
|
+
\${({ theme }) => styledText(theme)};
|
|
197
|
+
color: \${({ theme, $isActive }) =>
|
|
198
|
+
$isActive ? theme.colors.primary : theme.colors.dark};
|
|
199
|
+
font-weight: \${({ $isActive }) => ($isActive ? "600" : "400")};
|
|
200
|
+
text-decoration: none;
|
|
201
|
+
transition: all 0.3s ease;
|
|
202
|
+
|
|
203
|
+
&:hover {
|
|
204
|
+
color: \${({ theme }) => theme.colors.primaryDark};
|
|
195
205
|
}
|
|
196
206
|
\`;
|
|
197
207
|
|