doccupine 0.0.88 → 0.0.89
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/README.md +15 -2
- package/dist/index.js +79 -4
- package/dist/lib/layout.js +38 -24
- package/dist/lib/metadata.d.ts +30 -0
- package/dist/lib/metadata.js +98 -1
- package/dist/templates/app/theme.d.ts +1 -1
- package/dist/templates/app/theme.js +84 -19
- package/dist/templates/components/Chat.d.ts +1 -1
- package/dist/templates/components/Chat.js +26 -27
- package/dist/templates/components/SearchModalContent.d.ts +1 -1
- package/dist/templates/components/SearchModalContent.js +12 -6
- package/dist/templates/components/SideBar.d.ts +1 -1
- package/dist/templates/components/SideBar.js +3 -1
- package/dist/templates/components/layout/Accordion.d.ts +1 -1
- package/dist/templates/components/layout/Accordion.js +2 -1
- package/dist/templates/components/layout/ActionBar.d.ts +1 -1
- package/dist/templates/components/layout/ActionBar.js +4 -6
- package/dist/templates/components/layout/Button.d.ts +1 -1
- package/dist/templates/components/layout/Button.js +10 -0
- package/dist/templates/components/layout/Callout.d.ts +1 -1
- package/dist/templates/components/layout/Callout.js +75 -20
- package/dist/templates/components/layout/Card.d.ts +1 -1
- package/dist/templates/components/layout/Card.js +2 -1
- package/dist/templates/components/layout/CherryThemeProvider.d.ts +1 -1
- package/dist/templates/components/layout/CherryThemeProvider.js +6 -12
- package/dist/templates/components/layout/ClientThemeProvider.d.ts +1 -1
- package/dist/templates/components/layout/ClientThemeProvider.js +45 -40
- package/dist/templates/components/layout/Code.d.ts +1 -1
- package/dist/templates/components/layout/Code.js +223 -255
- package/dist/templates/components/layout/ColorSwatch.d.ts +1 -1
- package/dist/templates/components/layout/ColorSwatch.js +2 -2
- package/dist/templates/components/layout/Columns.d.ts +1 -1
- package/dist/templates/components/layout/Columns.js +1 -1
- package/dist/templates/components/layout/DemoTheme.d.ts +1 -1
- package/dist/templates/components/layout/DemoTheme.js +65 -167
- package/dist/templates/components/layout/DocsComponents.d.ts +1 -1
- package/dist/templates/components/layout/DocsComponents.js +13 -19
- package/dist/templates/components/layout/Field.d.ts +1 -1
- package/dist/templates/components/layout/Field.js +6 -4
- package/dist/templates/components/layout/Footer.d.ts +1 -1
- package/dist/templates/components/layout/Footer.js +1 -2
- package/dist/templates/components/layout/GlobalStyles.d.ts +1 -1
- package/dist/templates/components/layout/GlobalStyles.js +63 -10
- package/dist/templates/components/layout/Header.d.ts +1 -1
- package/dist/templates/components/layout/Header.js +14 -11
- package/dist/templates/components/layout/SharedStyles.d.ts +1 -1
- package/dist/templates/components/layout/SharedStyles.js +4 -5
- package/dist/templates/components/layout/StaticLinks.d.ts +1 -1
- package/dist/templates/components/layout/StaticLinks.js +4 -6
- package/dist/templates/components/layout/Steps.d.ts +1 -1
- package/dist/templates/components/layout/Steps.js +3 -3
- package/dist/templates/components/layout/Tabs.d.ts +1 -1
- package/dist/templates/components/layout/Tabs.js +5 -2
- package/dist/templates/components/layout/ThemeToggle.d.ts +1 -1
- package/dist/templates/components/layout/ThemeToggle.js +17 -19
- package/dist/templates/components/layout/Typography.d.ts +1 -1
- package/dist/templates/components/layout/Typography.js +1 -1
- package/dist/templates/components/layout/Update.d.ts +1 -1
- package/dist/templates/components/layout/Update.js +4 -3
- package/dist/templates/mdx/platform/site-settings.mdx.d.ts +1 -1
- package/dist/templates/mdx/platform/site-settings.mdx.js +5 -1
- package/dist/templates/package.js +0 -1
- package/dist/templates/proxy.js +14 -20
- package/package.json +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export const headerTemplate = `"use client";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { useCallback, useContext, useRef, useState } from "react";
|
|
4
|
-
import styled, { css
|
|
4
|
+
import styled, { css } from "styled-components";
|
|
5
5
|
import Link from "next/link";
|
|
6
|
-
import { rgba } from "polished";
|
|
7
6
|
import { mq, Theme } from "@/app/theme";
|
|
8
7
|
import { useOnClickOutside } from "@/components/ClickOutside";
|
|
9
8
|
import { Search } from "lucide-react";
|
|
@@ -52,7 +51,8 @@ const StyledHeader = styled.header<{ theme: Theme; $hasChildren: boolean }>\`
|
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
&::after {
|
|
55
|
-
background: \${({ theme }) =>
|
|
54
|
+
background: \${({ theme }) =>
|
|
55
|
+
\`color-mix(in srgb, \${theme.colors.primaryLight} 5%, transparent)\`};
|
|
56
56
|
z-index: -1;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -127,7 +127,6 @@ function Header({ children }: HeaderProps) {
|
|
|
127
127
|
isOptionActive ? closeMenu : () => {},
|
|
128
128
|
);
|
|
129
129
|
useOnClickOutside([langRef, wrapperRef], isLangActive ? closeMenu : () => {});
|
|
130
|
-
const theme = useTheme() as Theme;
|
|
131
130
|
const { isChatActive } = useContext(ChatContext);
|
|
132
131
|
const { openSearch } = useContext(SearchContext);
|
|
133
132
|
|
|
@@ -136,23 +135,27 @@ function Header({ children }: HeaderProps) {
|
|
|
136
135
|
<StyledHeaderInner $hasChildren={children ? true : false}>
|
|
137
136
|
<Link href="/" className="logo" aria-label="Logo">
|
|
138
137
|
{customThemeJson.logo ? (
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
<>
|
|
139
|
+
{/* Both logos render; .light-only and .dark-only classes in
|
|
140
|
+
GlobalStyles hide the inactive one based on the "dark" class
|
|
141
|
+
on <html>. Avoids a JS-driven swap so no flash on first load. */}
|
|
142
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
141
143
|
<img
|
|
142
|
-
|
|
144
|
+
className="light-only"
|
|
145
|
+
src={customThemeJson.logo.light}
|
|
143
146
|
alt="Logo"
|
|
144
147
|
width="100"
|
|
145
148
|
height="100"
|
|
146
149
|
/>
|
|
147
|
-
|
|
148
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
150
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
149
151
|
<img
|
|
150
|
-
|
|
152
|
+
className="dark-only"
|
|
153
|
+
src={customThemeJson.logo.dark}
|
|
151
154
|
alt="Logo"
|
|
152
155
|
width="100"
|
|
153
156
|
height="100"
|
|
154
157
|
/>
|
|
155
|
-
|
|
158
|
+
</>
|
|
156
159
|
) : (
|
|
157
160
|
<Logo />
|
|
158
161
|
)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const sharedStyledTemplate = "\"use client\";\nimport {
|
|
1
|
+
export declare const sharedStyledTemplate = "\"use client\";\nimport { styledSmall, styledText } from \"cherry-styled-components\";\nimport { mq, Theme } from \"@/app/theme\";\nimport styled, { css } from \"styled-components\";\n\nexport const interactiveStyles = css<{ theme: Theme }>`\n transition: all 0.3s ease;\n border: solid 1px transparent;\n box-shadow: 0 0 0 0px ${({ theme }) => theme.colors.primary};\n\n &:hover {\n border-color: ${({ theme }) => theme.colors.primary};\n }\n\n &:focus {\n border-color: ${({ theme }) => theme.colors.primary};\n box-shadow: 0 0 0 4px ${({ theme }) => theme.colors.primaryLight};\n }\n\n &:active {\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nexport const styledAnchor = css<{ theme: Theme }>`\n & a:not([class]):not(:has(img)) {\n color: inherit;\n transition: all 0.3s ease;\n text-decoration: none;\n box-shadow: 0 2px 0 0 ${({ theme }) => theme.colors.primary};\n\n &:hover {\n color: ${({ theme }) => theme.colors.accent};\n box-shadow: 0 1px 0 0 ${({ theme }) => theme.colors.primary};\n }\n }\n`;\n\nexport const stylesLists = css<{ theme: Theme }>`\n & ul,\n & ol {\n & li {\n & > .code-wrapper {\n margin: 10px 0;\n }\n }\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 & ul {\n padding-left: 15px;\n }\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 styledTable = css<{ theme: Theme }>`\n & .table-wrapper {\n overflow-x: auto;\n width: 100%;\n }\n\n & table {\n margin: 0;\n padding: 0;\n border-collapse: collapse;\n width: 100%;\n text-align: left;\n\n & tr {\n margin: 0;\n padding: 0;\n }\n\n & th {\n border-bottom: solid 1px ${({ theme }) => theme.colors.grayLight};\n padding: 10px 10px 10px 0;\n ${({ theme }) => styledSmall(theme)};\n font-weight: 600;\n color: ${({ theme }) => theme.colors.dark};\n }\n\n & td {\n border-bottom: solid 1px ${({ theme }) => theme.colors.grayLight};\n padding: 10px 10px 10px 0;\n color: ${({ theme }) => theme.colors.grayDark};\n ${({ theme }) => styledSmall(theme)};\n }\n }\n`;\n\nexport const StyledSmallButton = styled.button<{ theme: Theme }>`\n ${interactiveStyles};\n background: ${({ theme }) => theme.colors.light};\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n color: ${({ theme }) => theme.colors.accent};\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n padding: 6px 8px;\n font-size: 12px;\n font-family: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n margin-right: -6px;\n\n & svg.lucide {\n color: inherit;\n }\n`;\n";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const sharedStyledTemplate = `"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { styledSmall, styledText } from "cherry-styled-components";
|
|
3
|
+
import { mq, Theme } from "@/app/theme";
|
|
3
4
|
import styled, { css } from "styled-components";
|
|
4
5
|
|
|
5
6
|
export const interactiveStyles = css<{ theme: Theme }>\`
|
|
@@ -29,8 +30,7 @@ export const styledAnchor = css<{ theme: Theme }>\`
|
|
|
29
30
|
box-shadow: 0 2px 0 0 \${({ theme }) => theme.colors.primary};
|
|
30
31
|
|
|
31
32
|
&:hover {
|
|
32
|
-
color: \${({ theme }) =>
|
|
33
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
33
|
+
color: \${({ theme }) => theme.colors.accent};
|
|
34
34
|
box-shadow: 0 1px 0 0 \${({ theme }) => theme.colors.primary};
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -148,8 +148,7 @@ export const StyledSmallButton = styled.button<{ theme: Theme }>\`
|
|
|
148
148
|
\${interactiveStyles};
|
|
149
149
|
background: \${({ theme }) => theme.colors.light};
|
|
150
150
|
border: solid 1px \${({ theme }) => theme.colors.grayLight};
|
|
151
|
-
color: \${({ theme }) =>
|
|
152
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
151
|
+
color: \${({ theme }) => theme.colors.accent};
|
|
153
152
|
border-radius: \${({ theme }) => theme.spacing.radius.xs};
|
|
154
153
|
padding: 6px 8px;
|
|
155
154
|
font-size: 12px;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const staticLinksTemplate = "\"use client\";\nimport styled, { css } from \"styled-components\";\nimport {
|
|
1
|
+
export declare const staticLinksTemplate = "\"use client\";\nimport styled, { css } from \"styled-components\";\nimport { useContext } from \"react\";\nimport { ChatContext } from \"@/components/Chat\";\nimport { mq, Theme } from \"@/app/theme\";\nimport { interactiveStyles } from \"@/components/layout/SharedStyled\";\nimport { Icon } from \"@/components/layout/Icon\";\nimport linksData from \"@/links.json\";\n\ninterface LinkProps {\n title: string;\n url: string;\n icon?: string;\n}\n\nconst links = linksData as LinkProps[];\n\nconst StyledStaticLinks = styled.div<{ theme: Theme; $isChatOpen: boolean }>`\n display: flex;\n margin: 0 auto;\n transition: all 0.3s ease;\n padding: 0 20px;\n margin-bottom: 20px;\n\n ${mq(\"lg\")} {\n margin: 0;\n padding: 0 300px 20px 300px;\n\n ${({ $isChatOpen }) =>\n $isChatOpen &&\n css`\n padding: 0 440px 20px 300px;\n `}\n }\n`;\n\nconst StyledStaticLinksContent = styled.div`\n max-width: 640px;\n margin: auto 0;\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n width: 100%;\n margin: 0 auto;\n`;\n\nconst StyledLink = styled.a<{ theme: Theme; $hasIcon?: boolean }>`\n position: relative;\n text-decoration: none;\n font-size: ${({ theme }) => theme.fontSizes.small.lg};\n line-height: 1;\n color: ${({ theme }) => theme.colors.accent};\n padding: 0;\n display: flex;\n gap: 6px;\n transition: all 0.3s ease;\n font-weight: 600;\n white-space: nowrap;\n min-width: fit-content;\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 10%, transparent)`};\n padding: 6px 8px;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n ${interactiveStyles};\n\n ${({ $hasIcon }) =>\n $hasIcon &&\n css`\n padding-left: 30px;\n `}\n\n & * {\n margin: auto 0;\n }\n\n & svg {\n position: absolute;\n top: 50%;\n left: 8px;\n transform: translateY(-50%);\n }\n\n &:hover {\n color: ${({ theme }) => theme.colors.accent};\n }\n`;\n\nfunction StaticLinks() {\n const { isOpen } = useContext(ChatContext);\n\n if (links.length === 0) {\n return null;\n }\n\n return (\n <>\n <StyledStaticLinks $isChatOpen={isOpen}>\n <StyledStaticLinksContent>\n {links.map((link, index) => (\n <StyledLink\n key={index}\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n $hasIcon={link.icon ? true : false}\n >\n {link.icon && <Icon name={link.icon} size={16} />}\n <span>{link.title}</span>\n </StyledLink>\n ))}\n </StyledStaticLinksContent>\n </StyledStaticLinks>\n </>\n );\n}\n\nexport { StaticLinks };\n";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SIDEBAR_WIDTH, CHAT_WIDTH } from "../../app/theme.js";
|
|
2
2
|
export const staticLinksTemplate = `"use client";
|
|
3
3
|
import styled, { css } from "styled-components";
|
|
4
|
-
import { rgba } from "polished";
|
|
5
4
|
import { useContext } from "react";
|
|
6
5
|
import { ChatContext } from "@/components/Chat";
|
|
7
6
|
import { mq, Theme } from "@/app/theme";
|
|
@@ -51,8 +50,7 @@ const StyledLink = styled.a<{ theme: Theme; $hasIcon?: boolean }>\`
|
|
|
51
50
|
text-decoration: none;
|
|
52
51
|
font-size: \${({ theme }) => theme.fontSizes.small.lg};
|
|
53
52
|
line-height: 1;
|
|
54
|
-
color: \${({ theme }) =>
|
|
55
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
53
|
+
color: \${({ theme }) => theme.colors.accent};
|
|
56
54
|
padding: 0;
|
|
57
55
|
display: flex;
|
|
58
56
|
gap: 6px;
|
|
@@ -60,7 +58,8 @@ const StyledLink = styled.a<{ theme: Theme; $hasIcon?: boolean }>\`
|
|
|
60
58
|
font-weight: 600;
|
|
61
59
|
white-space: nowrap;
|
|
62
60
|
min-width: fit-content;
|
|
63
|
-
background: \${({ theme }) =>
|
|
61
|
+
background: \${({ theme }) =>
|
|
62
|
+
\`color-mix(in srgb, \${theme.colors.primaryLight} 10%, transparent)\`};
|
|
64
63
|
padding: 6px 8px;
|
|
65
64
|
border-radius: \${({ theme }) => theme.spacing.radius.xs};
|
|
66
65
|
\${interactiveStyles};
|
|
@@ -83,8 +82,7 @@ const StyledLink = styled.a<{ theme: Theme; $hasIcon?: boolean }>\`
|
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
&:hover {
|
|
86
|
-
color: \${({ theme }) =>
|
|
87
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
85
|
+
color: \${({ theme }) => theme.colors.accent};
|
|
88
86
|
}
|
|
89
87
|
\`;
|
|
90
88
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const stepsTemplate = "\"use client\";\nimport React from \"react\";\nimport styled, { useTheme } from \"styled-components\";\nimport { styledText
|
|
1
|
+
export declare const stepsTemplate = "\"use client\";\nimport React from \"react\";\nimport styled, { useTheme } from \"styled-components\";\nimport { styledText } from \"cherry-styled-components\";\nimport { Theme } from \"@/app/theme\";\nimport { Icon, IconProps } from \"@/components/layout/Icon\";\n\nconst StyledStepsContainer = styled.div<{ theme: Theme }>`\n position: relative;\n width: 100%;\n`;\n\nconst StyledStep = styled.div<{ theme: Theme }>`\n background: ${({ theme }) => theme.colors.light};\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n padding: 0 0 20px 52px;\n margin: 0;\n position: relative;\n ${({ theme }) => styledText(theme)}\n color: ${({ theme }) => theme.colors.grayDark};\n\n &::after {\n content: \"\";\n position: absolute;\n left: 16px;\n top: 0;\n width: 1px;\n height: 100%;\n background: ${({ theme }) => theme.colors.primary};\n background: linear-gradient(\n 180deg,\n ${({ theme }) => theme.colors.primary},\n transparent\n );\n border-radius: 4px;\n }\n`;\n\nconst StepNumber = styled.div<{ theme: Theme }>`\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: ${({ theme }) => theme.colors.primary};\n color: ${({ theme }) => theme.colors.light};\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 700;\n margin-bottom: 12px;\n ${({ theme }) => styledText(theme)};\n position: absolute;\n left: 0;\n top: 0;\n z-index: 1;\n`;\n\nconst StyledStepTitle = styled.h3<{ theme: Theme }>`\n margin: 0 0 10px 0;\n padding: 2px 0 0 0;\n color: ${({ theme }) => theme.colors.dark};\n ${({ theme }) => styledText(theme)};\n display: flex;\n align-items: center;\n gap: 10px;\n`;\n\nconst StepContent = styled.div<{ theme: Theme }>`\n color: ${({ theme }) => theme.colors.grayDark};\n ${({ theme }) => styledText(theme)};\n\n & > .code-wrapper {\n margin: 10px 0;\n }\n`;\n\ninterface StepProps extends React.HTMLAttributes<HTMLDivElement> {\n title: string;\n children: React.ReactNode;\n icon?: IconProps;\n}\n\nfunction Step(_props: StepProps) {\n return null;\n}\n\ninterface StepsProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n}\n\nfunction Steps({ children }: StepsProps) {\n const theme = useTheme() as Theme;\n\n const steps = React.Children.toArray(children).filter(\n (child): child is React.ReactElement<StepProps> =>\n React.isValidElement(child),\n );\n\n return (\n <StyledStepsContainer theme={theme}>\n {steps.map((step, index) => {\n const { title, children: stepContent, icon } = step.props;\n\n return (\n <StyledStep key={index} theme={theme}>\n <StepNumber theme={theme}>{index + 1}</StepNumber>\n <StyledStepTitle theme={theme}>\n {icon && <Icon name={icon} color={theme.colors.primary} />}\n {title}\n </StyledStepTitle>\n <StepContent theme={theme}>{stepContent}</StepContent>\n </StyledStep>\n );\n })}\n </StyledStepsContainer>\n );\n}\n\nexport { Steps, Step };\n";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const stepsTemplate = `"use client";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import styled, { useTheme } from "styled-components";
|
|
4
|
-
import { styledText
|
|
5
|
-
import {
|
|
4
|
+
import { styledText } from "cherry-styled-components";
|
|
5
|
+
import { Theme } from "@/app/theme";
|
|
6
6
|
import { Icon, IconProps } from "@/components/layout/Icon";
|
|
7
7
|
|
|
8
8
|
const StyledStepsContainer = styled.div<{ theme: Theme }>\`
|
|
@@ -30,7 +30,7 @@ const StyledStep = styled.div<{ theme: Theme }>\`
|
|
|
30
30
|
background: linear-gradient(
|
|
31
31
|
180deg,
|
|
32
32
|
\${({ theme }) => theme.colors.primary},
|
|
33
|
-
|
|
33
|
+
transparent
|
|
34
34
|
);
|
|
35
35
|
border-radius: 4px;
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const tabsTemplate = "\"use client\";\nimport { Theme } from \"@/app/theme\";\nimport { styledText } from \"cherry-styled-components\";\nimport
|
|
1
|
+
export declare const tabsTemplate = "\"use client\";\nimport { Theme } from \"@/app/theme\";\nimport { styledText } from \"cherry-styled-components\";\nimport React, { useState, ReactNode } from \"react\";\nimport styled, { css } from \"styled-components\";\ninterface TabContentProps {\n title: string;\n children: ReactNode;\n}\ninterface TabsProps {\n children: React.ReactElement<TabContentProps>[];\n}\nconst TabsContainer = styled.div`\n width: 100%;\n margin: 0 auto;\n`;\nconst TabsList = styled.div<{ theme: Theme }>`\n display: flex;\n overflow: hidden;\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n background-color: ${({ theme }) => theme.colors.light};\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n overflow-x: auto;\n`;\nconst TabButton = styled.button<{ theme: Theme; $isActive?: boolean }>`\n flex: 1;\n padding: 12px 20px;\n border: none;\n background: ${({ theme }) => theme.colors.light};\n cursor: pointer;\n transition: all 0.2s ease;\n border-bottom: 3px solid transparent;\n min-width: fit-content;\n ${({ theme }) => styledText(theme)};\n color: ${({ theme }) => theme.colors.dark};\n font-weight: 600;\n ${({ theme, $isActive }) =>\n $isActive &&\n css`\n color: ${theme.colors.primary};\n border-bottom: 3px solid ${theme.colors.primary};\n `}\n position: relative;\n &:hover {\n ${({ theme, $isActive }) =>\n !$isActive &&\n css`\n color: ${theme.colors.primary};\n background-color: color-mix(\n in srgb,\n ${theme.colors.primaryLight} 10%,\n transparent\n );\n `}\n }\n &:focus {\n outline: none;\n }\n &:not(:last-child) {\n border-right: 1px solid ${({ theme }) => theme.colors.grayLight};\n }\n`;\nconst TabPanel = styled.div<{ theme: Theme }>`\n background-color: ${({ theme }) => theme.colors.light};\n padding: 20px;\n border-radius: 0 0 ${({ theme }) => theme.spacing.radius.lg}\n ${({ theme }) => theme.spacing.radius.lg};\n color: ${({ theme }) => theme.colors.grayDark};\n ${({ theme }) => styledText(theme)}\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-top: none;\n display: flex;\n flex-direction: column;\n gap: 20px;\n flex-wrap: wrap;\n flex: 1;\n`;\nconst TabContent: React.FC<TabContentProps> = ({ children }) => {\n return <>{children}</>;\n};\nconst Tabs: React.FC<TabsProps> = ({ children }) => {\n const [activeTab, setActiveTab] = useState(0);\n const tabs = React.Children.toArray(children).filter(\n (child): child is React.ReactElement<TabContentProps> =>\n Boolean(\n React.isValidElement(child) &&\n child.props &&\n typeof child.props === \"object\" &&\n \"title\" in child.props &&\n typeof child.props.title === \"string\" &&\n child.props.title.trim() !== \"\",\n ),\n );\n return (\n <TabsContainer>\n <TabsList>\n {tabs.map((tab, index) => (\n <TabButton\n key={index}\n $isActive={activeTab === index}\n onClick={() => setActiveTab(index)}\n type=\"button\"\n >\n {tab.props.title}\n </TabButton>\n ))}\n </TabsList>\n <TabPanel>{tabs[activeTab]?.props.children}</TabPanel>\n </TabsContainer>\n );\n};\nexport { Tabs, TabContent };\n";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export const tabsTemplate = `"use client";
|
|
2
2
|
import { Theme } from "@/app/theme";
|
|
3
3
|
import { styledText } from "cherry-styled-components";
|
|
4
|
-
import { rgba } from "polished";
|
|
5
4
|
import React, { useState, ReactNode } from "react";
|
|
6
5
|
import styled, { css } from "styled-components";
|
|
7
6
|
interface TabContentProps {
|
|
@@ -49,7 +48,11 @@ const TabButton = styled.button<{ theme: Theme; $isActive?: boolean }>\`
|
|
|
49
48
|
!$isActive &&
|
|
50
49
|
css\`
|
|
51
50
|
color: \${theme.colors.primary};
|
|
52
|
-
background-color:
|
|
51
|
+
background-color: color-mix(
|
|
52
|
+
in srgb,
|
|
53
|
+
\${theme.colors.primaryLight} 10%,
|
|
54
|
+
transparent
|
|
55
|
+
);
|
|
53
56
|
\`}
|
|
54
57
|
}
|
|
55
58
|
&:focus {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const themeToggleTemplate = "\"use client\";\nimport {
|
|
1
|
+
export declare const themeToggleTemplate = "\"use client\";\nimport { resetButton } from \"cherry-styled-components\";\nimport styled, { css } from \"styled-components\";\nimport { Theme } from \"@/app/theme\";\nimport { Icon } from \"@/components/layout/Icon\";\nimport { useThemeOverride } from \"@/components/layout/ClientThemeProvider\";\n\nconst StyledThemeToggle = styled.button<{ theme: Theme; $hidden?: boolean }>`\n ${resetButton}\n width: 59px;\n height: 32px;\n border-radius: 30px;\n display: flex;\n position: relative;\n margin: auto 0;\n transform: scale(1);\n background: ${({ theme }) => theme.colors.light};\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n\n &::after {\n content: \"\";\n position: absolute;\n top: 3px;\n left: 3px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 20%, transparent)`};\n transition: all 0.3s ease;\n z-index: 1;\n }\n\n /* Knob position depends on the active mode, signaled by the \"dark\" class\n on <html>. Pure CSS \u2014 no JS conditional needed for the visual swap. */\n :root.dark &::after {\n transform: translateX(27px);\n }\n\n ${({ $hidden }) =>\n $hidden &&\n css`\n display: none;\n `}\n\n & svg {\n width: 16px;\n height: 16px;\n object-fit: contain;\n margin: auto;\n transition: all 0.3s ease;\n position: relative;\n z-index: 2;\n }\n\n & .lucide-sun {\n transform: translateX(1px);\n }\n\n & .lucide-moon-star {\n transform: translateX(-1px);\n }\n\n & svg[stroke] {\n stroke: ${({ theme }) => theme.colors.primary};\n }\n\n &:hover {\n transform: scale(1.05);\n color: ${({ theme }) => theme.colors.accent};\n\n & svg[stroke] {\n stroke: ${({ theme }) => theme.colors.accent};\n }\n }\n\n &:active {\n transform: scale(0.97);\n }\n`;\n\nfunction ToggleTheme({ $hidden }: { $hidden?: boolean }) {\n const { mode, setMode } = useThemeOverride();\n\n return (\n <StyledThemeToggle\n onClick={async () => {\n const next = mode === \"dark\" ? \"light\" : \"dark\";\n setMode(next);\n await fetch(\"/api/theme\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ theme: next }),\n }).catch((err) => console.error(\"Failed to persist theme:\", err));\n }}\n $hidden={$hidden}\n aria-label=\"Toggle Theme\"\n >\n <Icon name=\"Sun\" className=\"light\" />\n <Icon name=\"MoonStar\" className=\"dark\" />\n </StyledThemeToggle>\n );\n}\n\nfunction ToggleThemeLoading() {\n return (\n <StyledThemeToggle $hidden aria-label=\"Toggle Theme\">\n <Icon name=\"MoonStar\" className=\"dark\" />\n <Icon name=\"Sun\" className=\"light\" />\n </StyledThemeToggle>\n );\n}\n\nexport { ToggleTheme, ToggleThemeLoading };\n";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export const themeToggleTemplate = `"use client";
|
|
2
|
-
import {
|
|
3
|
-
import styled, { css
|
|
4
|
-
import {
|
|
2
|
+
import { resetButton } from "cherry-styled-components";
|
|
3
|
+
import styled, { css } from "styled-components";
|
|
4
|
+
import { Theme } from "@/app/theme";
|
|
5
5
|
import { Icon } from "@/components/layout/Icon";
|
|
6
|
-
import { theme as themeLight, themeDark } from "@/app/theme";
|
|
7
6
|
import { useThemeOverride } from "@/components/layout/ClientThemeProvider";
|
|
8
7
|
|
|
9
8
|
const StyledThemeToggle = styled.button<{ theme: Theme; $hidden?: boolean }>\`
|
|
@@ -26,14 +25,16 @@ const StyledThemeToggle = styled.button<{ theme: Theme; $hidden?: boolean }>\`
|
|
|
26
25
|
width: 24px;
|
|
27
26
|
height: 24px;
|
|
28
27
|
border-radius: 50%;
|
|
29
|
-
background: \${({ theme }) =>
|
|
28
|
+
background: \${({ theme }) =>
|
|
29
|
+
\`color-mix(in srgb, \${theme.colors.primaryLight} 20%, transparent)\`};
|
|
30
30
|
transition: all 0.3s ease;
|
|
31
31
|
z-index: 1;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Knob position depends on the active mode, signaled by the "dark" class
|
|
35
|
+
on <html>. Pure CSS — no JS conditional needed for the visual swap. */
|
|
36
|
+
:root.dark &::after {
|
|
37
|
+
transform: translateX(27px);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
\${({ $hidden }) =>
|
|
@@ -66,12 +67,10 @@ const StyledThemeToggle = styled.button<{ theme: Theme; $hidden?: boolean }>\`
|
|
|
66
67
|
|
|
67
68
|
&:hover {
|
|
68
69
|
transform: scale(1.05);
|
|
69
|
-
color: \${({ theme }) =>
|
|
70
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
70
|
+
color: \${({ theme }) => theme.colors.accent};
|
|
71
71
|
|
|
72
72
|
& svg[stroke] {
|
|
73
|
-
stroke: \${({ theme }) =>
|
|
74
|
-
theme.isDark ? theme.colors.primaryLight : theme.colors.primaryDark};
|
|
73
|
+
stroke: \${({ theme }) => theme.colors.accent};
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -81,18 +80,17 @@ const StyledThemeToggle = styled.button<{ theme: Theme; $hidden?: boolean }>\`
|
|
|
81
80
|
\`;
|
|
82
81
|
|
|
83
82
|
function ToggleTheme({ $hidden }: { $hidden?: boolean }) {
|
|
84
|
-
const {
|
|
85
|
-
const theme = useTheme() as Theme;
|
|
83
|
+
const { mode, setMode } = useThemeOverride();
|
|
86
84
|
|
|
87
85
|
return (
|
|
88
86
|
<StyledThemeToggle
|
|
89
87
|
onClick={async () => {
|
|
90
|
-
const
|
|
91
|
-
|
|
88
|
+
const next = mode === "dark" ? "light" : "dark";
|
|
89
|
+
setMode(next);
|
|
92
90
|
await fetch("/api/theme", {
|
|
93
91
|
method: "POST",
|
|
94
92
|
headers: { "Content-Type": "application/json" },
|
|
95
|
-
body: JSON.stringify({ theme:
|
|
93
|
+
body: JSON.stringify({ theme: next }),
|
|
96
94
|
}).catch((err) => console.error("Failed to persist theme:", err));
|
|
97
95
|
}}
|
|
98
96
|
$hidden={$hidden}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const typographyTemplate = "\"use client\";\nimport {\n styledH1,\n styledH2,\n styledH3,\n styledH4,\n styledH5,\n styledH6,\n styledText,\n
|
|
1
|
+
export declare const typographyTemplate = "\"use client\";\nimport {\n styledH1,\n styledH2,\n styledH3,\n styledH4,\n styledH5,\n styledH6,\n styledText,\n} from \"cherry-styled-components\";\nimport styled, { css } from \"styled-components\";\nimport { Theme } from \"@/app/theme\";\n\nconst StyledHeading = css`\n font-weight: 900;\n`;\n\nexport const StyledH1 = styled.h1<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH1(theme)}\n`;\n\nexport const StyledH2 = styled.h2<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH2(theme)}\n`;\n\nexport const StyledH3 = styled.h3<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH3(theme)}\n`;\n\nexport const StyledH4 = styled.h4<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH4(theme)}\n`;\n\nexport const StyledH5 = styled.h5<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH5(theme)}\n`;\n\nexport const StyledH6 = styled.h6<{ theme: Theme }>`\n ${StyledHeading};\n ${({ theme }) => styledH6(theme)}\n`;\n\nexport const StyledText = styled.p<{ theme: Theme }>`\n ${({ theme }) => styledText(theme)}\n`;\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const updateTemplate = "\"use client\";\nimport styled from \"styled-components\";\nimport {
|
|
1
|
+
export declare const updateTemplate = "\"use client\";\nimport styled from \"styled-components\";\nimport { styledSmall } from \"cherry-styled-components\";\nimport { mq, Theme } from \"@/app/theme\";\n\nconst StyledUpdate = styled.div<{ theme: Theme; $columns?: number }>`\n position: relative;\n display: flex;\n gap: 20px;\n flex-direction: column;\n\n ${mq(\"lg\")} {\n margin: 20px 0;\n flex-direction: row;\n }\n`;\n\nconst StyledUpdateLabel = styled.span<{ theme: Theme }>`\n background: ${({ theme }) =>\n `color-mix(in srgb, ${theme.colors.primaryLight} 20%, transparent)`};\n color: ${({ theme }) => theme.colors.primary};\n padding: 2px 4px;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n font-weight: 600;\n ${({ theme }) => styledSmall(theme)};\n`;\n\nconst StyledUpdateDescription = styled.div<{ theme: Theme }>`\n ${({ theme }) => styledSmall(theme)};\n color: ${({ theme }) => theme.colors.gray};\n`;\n\nconst StyledUpdateSidebar = styled.div`\n display: flex;\n flex-direction: column;\n gap: 10px;\n\n ${mq(\"lg\")} {\n min-width: 160px;\n }\n`;\n\nconst StyledUpdateChildren = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n`;\n\ninterface UpdateProps extends React.HTMLAttributes<HTMLDivElement> {\n children: React.ReactNode;\n label: string;\n description: string;\n}\n\nfunction Update({ children, label, description }: UpdateProps) {\n return (\n <StyledUpdate>\n <StyledUpdateSidebar>\n <div>\n <StyledUpdateLabel>{label}</StyledUpdateLabel>\n </div>\n <StyledUpdateDescription>{description}</StyledUpdateDescription>\n </StyledUpdateSidebar>\n <StyledUpdateChildren>{children}</StyledUpdateChildren>\n </StyledUpdate>\n );\n}\n\nexport { Update };\n";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const updateTemplate = `"use client";
|
|
2
2
|
import styled from "styled-components";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { styledSmall } from "cherry-styled-components";
|
|
4
|
+
import { mq, Theme } from "@/app/theme";
|
|
5
5
|
|
|
6
6
|
const StyledUpdate = styled.div<{ theme: Theme; $columns?: number }>\`
|
|
7
7
|
position: relative;
|
|
@@ -16,7 +16,8 @@ const StyledUpdate = styled.div<{ theme: Theme; $columns?: number }>\`
|
|
|
16
16
|
\`;
|
|
17
17
|
|
|
18
18
|
const StyledUpdateLabel = styled.span<{ theme: Theme }>\`
|
|
19
|
-
background: \${({ theme }) =>
|
|
19
|
+
background: \${({ theme }) =>
|
|
20
|
+
\`color-mix(in srgb, \${theme.colors.primaryLight} 20%, transparent)\`};
|
|
20
21
|
color: \${({ theme }) => theme.colors.primary};
|
|
21
22
|
padding: 2px 4px;
|
|
22
23
|
border-radius: \${({ theme }) => theme.spacing.radius.xs};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const platformSiteSettingsMdxTemplate = "---\ntitle: \"Site Settings\"\ndescription: \"Configure your documentation site's name, description, icon, and image.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 2\norder: 0\nsection: \"Platform\"\n---\n# Site Settings\nThe Site settings page lets you configure the core metadata for your documentation site. These values are stored in `config.json` at the root of your repository.\n\n## Fields\n\n### Name\nThe name of your documentation site. This appears in the site header and browser tab title.\n\n### Description\nA short description of your documentation. Used in meta tags for search engine optimization and social media previews.\n\n### Favicon\nUpload a favicon image that appears in browser tabs. Supported formats include PNG, ICO, and SVG. Use the file upload button to select an image from your computer.\n\n### Preview image\nUpload an image used for social media and OpenGraph previews. This is the image that appears when your documentation URL is shared on platforms like Twitter, Slack, or Discord.\n\n<Callout type=\"note\">\n Changes to site settings are staged as pending changes, just like file edits. Click **Publish** to commit them to your repository and trigger a deploy.\n</Callout>\n\n## How it works\nBehind the scenes, the Site settings page reads and writes `config.json` in your repository. You can also edit this file directly in the file editor if you prefer. See the [Globals](/globals) page for the full configuration reference.\n\n```json\n{\n \"name\": \"My Documentation\",\n \"description\": \"Documentation for my project\",\n \"icon\": \"/favicon.png\",\n \"image\": \"/preview.png\"\n}\n```";
|
|
1
|
+
export declare const platformSiteSettingsMdxTemplate = "---\ntitle: \"Site Settings\"\ndescription: \"Configure your documentation site's name, description, icon, and image.\"\ndate: \"2026-02-19\"\ncategory: \"Configuration\"\ncategoryOrder: 2\norder: 0\nsection: \"Platform\"\n---\n# Site Settings\nThe Site settings page lets you configure the core metadata for your documentation site. These values are stored in `config.json` at the root of your repository.\n\n## Fields\n\n### Name\nThe name of your documentation site. This appears in the site header and browser tab title.\n\n### Description\nA short description of your documentation. Used in meta tags for search engine optimization and social media previews.\n\n### Favicon\nUpload a favicon image that appears in browser tabs. Supported formats include PNG, ICO, and SVG. Use the file upload button to select an image from your computer.\n\n### Preview image\nUpload an image used for social media and OpenGraph previews. This is the image that appears when your documentation URL is shared on platforms like Twitter, Slack, or Discord.\n\n### Site URL\nThe public URL of your deployed documentation site, such as `https://docs.example.com`. This value is used as the base URL when generating `sitemap.xml` and `robots.txt`, so search engines can discover and index your pages correctly. You can override this at deploy time by setting the `NEXT_PUBLIC_SITE_URL` environment variable.\n\n<Callout type=\"note\">\n Changes to site settings are staged as pending changes, just like file edits. Click **Publish** to commit them to your repository and trigger a deploy.\n</Callout>\n\n## How it works\nBehind the scenes, the Site settings page reads and writes `config.json` in your repository. You can also edit this file directly in the file editor if you prefer. See the [Globals](/globals) page for the full configuration reference.\n\n```json\n{\n \"name\": \"My Documentation\",\n \"description\": \"Documentation for my project\",\n \"icon\": \"/favicon.png\",\n \"image\": \"/preview.png\",\n \"url\": \"https://docs.example.com\"\n}\n```";
|
|
@@ -24,6 +24,9 @@ Upload a favicon image that appears in browser tabs. Supported formats include P
|
|
|
24
24
|
### Preview image
|
|
25
25
|
Upload an image used for social media and OpenGraph previews. This is the image that appears when your documentation URL is shared on platforms like Twitter, Slack, or Discord.
|
|
26
26
|
|
|
27
|
+
### Site URL
|
|
28
|
+
The public URL of your deployed documentation site, such as \`https://docs.example.com\`. This value is used as the base URL when generating \`sitemap.xml\` and \`robots.txt\`, so search engines can discover and index your pages correctly. You can override this at deploy time by setting the \`NEXT_PUBLIC_SITE_URL\` environment variable.
|
|
29
|
+
|
|
27
30
|
<Callout type="note">
|
|
28
31
|
Changes to site settings are staged as pending changes, just like file edits. Click **Publish** to commit them to your repository and trigger a deploy.
|
|
29
32
|
</Callout>
|
|
@@ -36,6 +39,7 @@ Behind the scenes, the Site settings page reads and writes \`config.json\` in yo
|
|
|
36
39
|
"name": "My Documentation",
|
|
37
40
|
"description": "Documentation for my project",
|
|
38
41
|
"icon": "/favicon.png",
|
|
39
|
-
"image": "/preview.png"
|
|
42
|
+
"image": "/preview.png",
|
|
43
|
+
"url": "https://docs.example.com"
|
|
40
44
|
}
|
|
41
45
|
\`\`\``;
|
package/dist/templates/proxy.js
CHANGED
|
@@ -58,6 +58,18 @@ function captureServerPageview(req: NextRequest, event: NextFetchEvent) {
|
|
|
58
58
|
? `export function proxy(req: NextRequest, event: NextFetchEvent)`
|
|
59
59
|
: `export function proxy(req: NextRequest)`;
|
|
60
60
|
const eventImport = hasPostHog ? ", NextFetchEvent" : "";
|
|
61
|
+
// Matcher scope:
|
|
62
|
+
// - With PostHog server-side tracking: run on every path so pageviews
|
|
63
|
+
// fire (the capture function uses event.waitUntil and never mutates
|
|
64
|
+
// the response, so doc pages remain edge-cacheable).
|
|
65
|
+
// - Otherwise: only run on /api/* — the only routes that need middleware
|
|
66
|
+
// (e.g. MCP key auth). Doc pages bypass middleware entirely.
|
|
67
|
+
//
|
|
68
|
+
// Theme detection happens client-side via the theme-init blocking script
|
|
69
|
+
// in the root layout (sets a "dark" class on <html>). Middleware no longer
|
|
70
|
+
// sets Vary, Accept-CH, or a theme cookie, because doing so would mark
|
|
71
|
+
// every response as dynamic and disable caching at Vercel/Cloudflare.
|
|
72
|
+
const matcher = hasPostHog ? `["/:path*"]` : `["/api/:path*"]`;
|
|
61
73
|
return `import { NextResponse } from "next/server";
|
|
62
74
|
import type { NextRequest${eventImport} } from "next/server";
|
|
63
75
|
${posthogImport}${posthogPageviewFn}
|
|
@@ -77,29 +89,11 @@ ${posthogCall} // API key auth for /api/mcp when DOCS_API_KEY is configured
|
|
|
77
89
|
}
|
|
78
90
|
}
|
|
79
91
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
res.headers.set("Accept-CH", "Sec-CH-Prefers-Color-Scheme");
|
|
83
|
-
res.headers.set("Vary", "Sec-CH-Prefers-Color-Scheme");
|
|
84
|
-
res.headers.set("Critical-CH", "Sec-CH-Prefers-Color-Scheme");
|
|
85
|
-
|
|
86
|
-
const existing = req.cookies.get("theme")?.value;
|
|
87
|
-
const hint = req.headers.get("Sec-CH-Prefers-Color-Scheme");
|
|
88
|
-
|
|
89
|
-
if (!existing && hint) {
|
|
90
|
-
const value = hint === "dark" ? "dark" : "light";
|
|
91
|
-
res.cookies.set("theme", value, {
|
|
92
|
-
path: "/",
|
|
93
|
-
maxAge: 60 * 60 * 24 * 365,
|
|
94
|
-
sameSite: "lax",
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return res;
|
|
92
|
+
return NextResponse.next();
|
|
99
93
|
}
|
|
100
94
|
|
|
101
95
|
export const config = {
|
|
102
|
-
matcher:
|
|
96
|
+
matcher: ${matcher},
|
|
103
97
|
};
|
|
104
98
|
`;
|
|
105
99
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doccupine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.89",
|
|
4
4
|
"description": "Free and open-source documentation platform. Write MDX, get a production-ready site with AI chat, built-in components, and an MCP server - in one command.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|