mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
UI: Move to tsc (experimental)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-ui': minor
|
||||
---
|
||||
|
||||
Move to `tsc` (experimental)
|
||||
@@ -14,21 +14,11 @@ const docsOptions: DocsLayoutProps = {
|
||||
tree: source.pageTree,
|
||||
nav: {
|
||||
...baseOptions.nav,
|
||||
title: logo,
|
||||
children: (
|
||||
<Trigger
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: 'secondary',
|
||||
size: 'xs',
|
||||
className:
|
||||
'md:flex-1 px-2 ms-2 gap-1.5 text-fd-muted-foreground rounded-full',
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-3" />
|
||||
Ask AI
|
||||
</Trigger>
|
||||
title: (
|
||||
<>
|
||||
{logo}
|
||||
Fumadocs
|
||||
</>
|
||||
),
|
||||
},
|
||||
links: [linkItems[linkItems.length - 1]],
|
||||
@@ -42,7 +32,7 @@ const docsOptions: DocsLayoutProps = {
|
||||
...option,
|
||||
icon: (
|
||||
<Slot
|
||||
className="mb-auto bg-gradient-to-t from-fd-background/80 p-1 [&_svg]:size-5"
|
||||
className="bg-gradient-to-t from-fd-background/80 p-1 [&_svg]:size-5"
|
||||
style={{
|
||||
color: `hsl(var(--${meta.file.dirname}-color))`,
|
||||
backgroundColor: `hsl(var(--${meta.file.dirname}-color)/.3)`,
|
||||
@@ -57,11 +47,7 @@ const docsOptions: DocsLayoutProps = {
|
||||
},
|
||||
};
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
}): React.ReactElement {
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<DocsLayout {...docsOptions}>
|
||||
<span
|
||||
@@ -158,6 +144,17 @@ export default function Layout({
|
||||
</svg>
|
||||
</span>
|
||||
{children}
|
||||
<Trigger
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: 'secondary',
|
||||
}),
|
||||
'fixed bottom-0 left-1/2 h-fit -translate-x-1/2 gap-1.5 rounded-b-none rounded-t-2xl bg-secondary/50 pb-1 text-fd-muted-foreground shadow-lg backdrop-blur-lg',
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-4" />
|
||||
Ask AI
|
||||
</Trigger>
|
||||
</DocsLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}): React.ReactElement {
|
||||
}) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
|
||||
@@ -10,7 +10,7 @@ const buttonVariants = cva(
|
||||
outline:
|
||||
'border bg-gradient-to-t from-fd-primary/10 shadow-inner shadow-fd-primary/10 hover:bg-fd-accent/50 hover:text-fd-accent-foreground',
|
||||
secondary:
|
||||
'border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-secondary/80',
|
||||
'border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-accent',
|
||||
ghost: 'hover:bg-fd-accent hover:text-fd-accent-foreground',
|
||||
link: 'text-fd-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ function Route({ route }: { route: string }): ReactNode {
|
||||
const segments = route.split('/').filter((part) => part.length > 0);
|
||||
|
||||
return (
|
||||
<div className="not-prose flex flex-row items-center gap-1 overflow-auto text-xs">
|
||||
<div className="not-prose flex flex-row items-center gap-1 overflow-auto text-nowrap text-xs">
|
||||
{segments.map((part, index) => (
|
||||
<Fragment key={index}>
|
||||
<span className="text-fd-muted-foreground">/</span>
|
||||
|
||||
@@ -53,11 +53,10 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm build:layout && pnpm build:tailwind",
|
||||
"build:layout": "tsup",
|
||||
"build:layout": "tsc --project tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
||||
"build:tailwind": "postcss css/*.css --dir dist && postcss src/components/*.css --dir dist/components",
|
||||
"clean": "rimraf dist",
|
||||
"dev": "concurrently \"pnpm dev:layout\" \"pnpm dev:tailwind\"",
|
||||
"dev:layout": "tsup --watch",
|
||||
"dev": "concurrently \"tsc -w --project tsconfig.build.json\" \"tsc-alias -w -p tsconfig.build.json\" \"pnpm dev:tailwind\"",
|
||||
"dev:tailwind": "postcss css/*.css --dir dist --watch",
|
||||
"lint": "eslint .",
|
||||
"types:check": "tsc --noEmit"
|
||||
@@ -77,6 +76,7 @@
|
||||
"fumadocs-core": "workspace:*",
|
||||
"next-themes": "^0.3.0",
|
||||
"react-medium-image-zoom": "^5.2.10",
|
||||
"lucide-react": "^0.454.0",
|
||||
"tailwind-merge": "^2.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -85,12 +85,12 @@
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "15.0.2",
|
||||
"postcss": "^8.4.47",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"postcss-lightningcss": "^1.0.1",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"tsc-alias": "^1.8.10",
|
||||
"tsconfig": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
'use client';
|
||||
export { useCopyButton as _useCopyButton } from '@/utils/use-copy-button';
|
||||
@@ -1,6 +1,3 @@
|
||||
declare const { _useCopyButton }: typeof import('./api.client');
|
||||
|
||||
export const useCopyButton = _useCopyButton;
|
||||
|
||||
export * from '@/utils/cn';
|
||||
export * from '@/components/ui/button';
|
||||
export { useCopyButton } from '@/utils/use-copy-button';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import { type ButtonHTMLAttributes } from 'react';
|
||||
import { SearchIcon } from 'lucide-react';
|
||||
import { useSearchContext } from '@/contexts/search';
|
||||
|
||||
@@ -127,8 +127,8 @@ export const Sidebar = memo(
|
||||
} as object
|
||||
}
|
||||
>
|
||||
<div className="flex size-full flex-col pt-2 md:ms-auto md:w-[var(--fd-sidebar-width)] md:border-e md:pt-4">
|
||||
<div className="flex flex-col gap-1 px-4 empty:hidden md:px-3 md:pb-2">
|
||||
<div className="flex size-full flex-col pt-2 md:ms-auto md:w-[var(--fd-sidebar-width)] md:max-w-full md:border-e md:pt-4">
|
||||
<div className="flex flex-col gap-2 px-4 empty:hidden md:px-3 md:pb-2">
|
||||
{props.banner}
|
||||
{tabs.length > 0 ? (
|
||||
<RootToggle options={tabs} className="-mx-2" />
|
||||
@@ -167,7 +167,7 @@ const SeparatorNode = memo(({ item }: { item: PageTree.Separator }) => {
|
||||
|
||||
SeparatorNode.displayName = 'SeparatorNode';
|
||||
|
||||
function RootNodeList(): ReactNode {
|
||||
function RootNodeList() {
|
||||
const { root } = useTreeContext();
|
||||
const { components } = useInternalContext();
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import { Moon, Sun } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { ChevronRight, Text } from 'lucide-react';
|
||||
import type { TOCItemType } from 'fumadocs-core/server';
|
||||
import * as Primitive from 'fumadocs-core/toc';
|
||||
import {
|
||||
type ReactElement,
|
||||
type ReactNode,
|
||||
useContext,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { type ReactNode, useContext, useMemo, useRef } from 'react';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { useI18n } from '@/contexts/i18n';
|
||||
import {
|
||||
@@ -34,13 +28,13 @@ export interface TOCProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Toc({ header, footer, children }: TOCProps): ReactElement {
|
||||
export function Toc({ header, footer, children }: TOCProps) {
|
||||
const { text } = useI18n();
|
||||
|
||||
return (
|
||||
<div
|
||||
data-toc=""
|
||||
className="sticky top-fd-layout-top h-[var(--fd-toc-height)] flex-1 pb-2 pt-12 max-lg:hidden"
|
||||
className="sticky top-fd-layout-top h-[var(--fd-toc-height)] flex-1 pb-2 pe-2 pt-12 max-lg:hidden"
|
||||
style={
|
||||
{
|
||||
'--fd-toc-height':
|
||||
@@ -48,7 +42,7 @@ export function Toc({ header, footer, children }: TOCProps): ReactElement {
|
||||
} as object
|
||||
}
|
||||
>
|
||||
<div className="flex h-full w-[var(--fd-toc-width)] flex-col gap-3 pe-2">
|
||||
<div className="flex h-full w-[var(--fd-toc-width)] max-w-full flex-col gap-3">
|
||||
{header}
|
||||
<h3 className="-ms-0.5 inline-flex items-center gap-1.5 text-sm text-fd-muted-foreground">
|
||||
<Text className="size-4" />
|
||||
@@ -61,7 +55,7 @@ export function Toc({ header, footer, children }: TOCProps): ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
function TocNav(props: { className?: string; children: ReactNode }): ReactNode {
|
||||
function TocNav(props: { className?: string; children: ReactNode }) {
|
||||
const { open } = useSidebar();
|
||||
const { isTransparent } = useContext(NavContext);
|
||||
|
||||
@@ -89,7 +83,7 @@ function TocNav(props: { className?: string; children: ReactNode }): ReactNode {
|
||||
export function TocPopover({
|
||||
items,
|
||||
...props
|
||||
}: TOCProps & { items: TOCItemType[]; className?: string }): ReactElement {
|
||||
}: TOCProps & { items: TOCItemType[]; className?: string }) {
|
||||
const { text } = useI18n();
|
||||
const active = Primitive.useActiveAnchor();
|
||||
const current = useMemo(() => {
|
||||
@@ -134,7 +128,7 @@ export function TOCItems({
|
||||
}: {
|
||||
items: TOCItemType[];
|
||||
isMenu?: boolean;
|
||||
}): React.ReactElement {
|
||||
}) {
|
||||
const { text } = useI18n();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const viewRef = useRef<HTMLDivElement>(null);
|
||||
@@ -171,7 +165,7 @@ export function TOCItems({
|
||||
);
|
||||
}
|
||||
|
||||
function TOCItem({ item }: { item: TOCItemType }): React.ReactElement {
|
||||
function TOCItem({ item }: { item: TOCItemType }) {
|
||||
return (
|
||||
<Primitive.TOCItem
|
||||
href={item.url}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import type { PageTree } from 'fumadocs-core/server';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import {
|
||||
|
||||
@@ -22,6 +22,8 @@ import {
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import type { SharedNavProps } from './shared';
|
||||
import type { LinkItemType } from '@/layouts/links';
|
||||
import { MenuItem } from '@/layouts/menu-item';
|
||||
|
||||
export function SubNav({
|
||||
title,
|
||||
@@ -92,7 +94,7 @@ export function SidebarCollapseTrigger(
|
||||
}
|
||||
|
||||
interface LinksMenuProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
items?: ReactNode;
|
||||
items: LinkItemType[];
|
||||
}
|
||||
|
||||
export function LinksMenu({ items, ...props }: LinksMenuProps): ReactNode {
|
||||
@@ -106,18 +108,9 @@ export function LinksMenu({ items, ...props }: LinksMenuProps): ReactNode {
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger {...props} />
|
||||
<PopoverContent className="flex flex-col p-1">{items}</PopoverContent>
|
||||
<PopoverContent className="flex flex-col p-1">
|
||||
{items?.map((item, i) => <MenuItem key={i} item={item} />)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export { IconItem } from '@/layouts/links';
|
||||
export { MenuItem } from '@/layouts/menu-item';
|
||||
export { NavProvider } from '@/components/layout/nav';
|
||||
export { Sidebar } from '@/components/layout/sidebar';
|
||||
export { TreeContextProvider } from '@/contexts/tree';
|
||||
export { ThemeToggle } from '@/components/layout/theme-toggle';
|
||||
export {
|
||||
LanguageToggle,
|
||||
LanguageToggleText,
|
||||
} from '@/components/layout/language-toggle';
|
||||
|
||||
@@ -6,26 +6,29 @@ import { notFound } from 'next/navigation';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { buttonVariants } from '@/components/ui/button';
|
||||
import type { SidebarProps } from '@/components/layout/sidebar';
|
||||
import { Sidebar, type SidebarProps } from '@/components/layout/sidebar';
|
||||
import { replaceOrDefault, type SharedNavProps } from '@/layouts/shared';
|
||||
import type { LinkItemType, IconItem as IconItemType } from '@/layouts/links';
|
||||
import {
|
||||
type LinkItemType,
|
||||
IconItem as IconItemType,
|
||||
IconItem,
|
||||
} from '@/layouts/links';
|
||||
import { getSidebarTabs, type TabOptions } from '@/utils/get-sidebar-tabs';
|
||||
import type { Option } from '@/components/layout/root-toggle';
|
||||
import { type BaseLayoutProps, getLinks } from './shared';
|
||||
|
||||
declare const {
|
||||
TreeContextProvider,
|
||||
SidebarCollapseTrigger,
|
||||
ThemeToggle,
|
||||
SubNav,
|
||||
import {
|
||||
LanguageToggle,
|
||||
LanguageToggleText,
|
||||
} from '@/components/layout/language-toggle';
|
||||
import {
|
||||
LinksMenu,
|
||||
Sidebar,
|
||||
IconItem,
|
||||
MenuItem,
|
||||
NavProvider,
|
||||
}: typeof import('./docs.client');
|
||||
SidebarCollapseTrigger,
|
||||
SubNav,
|
||||
} from '@/layouts/docs.client';
|
||||
import { MenuItem } from '@/layouts/nav-item';
|
||||
import { TreeContextProvider } from '@/contexts/tree';
|
||||
import { NavProvider } from '@/components/layout/nav';
|
||||
import { ThemeToggle } from '@/components/layout/theme-toggle';
|
||||
|
||||
const DynamicSidebar = dynamic(
|
||||
() => import('@/components/layout/dynamic-sidebar'),
|
||||
@@ -89,7 +92,7 @@ export function DocsLayout({
|
||||
|
||||
const footer = (
|
||||
<>
|
||||
<div className="flex flex-row items-center border-t py-2 empty:hidden max-md:gap-1.5 max-md:px-3 md:mx-3">
|
||||
<div className="flex flex-row items-center border-t p-3 empty:hidden max-md:gap-1.5">
|
||||
<SidebarFooter
|
||||
sidebarCollapsible={collapsible}
|
||||
i18n={i18n}
|
||||
@@ -152,7 +155,7 @@ function SidebarHeader({
|
||||
if (!props.title && !props.children && links.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-row items-center border-b pb-2 max-md:hidden">
|
||||
<div className="flex flex-row items-center max-md:hidden">
|
||||
{props.title ? (
|
||||
<Link
|
||||
href={props.url ?? '/'}
|
||||
@@ -164,9 +167,7 @@ function SidebarHeader({
|
||||
{props.children}
|
||||
{links.length > 0 ? (
|
||||
<LinksMenu
|
||||
items={links.map((item, i) => (
|
||||
<MenuItem key={i} item={item} />
|
||||
))}
|
||||
items={links}
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
size: 'icon',
|
||||
|
||||
@@ -2,8 +2,7 @@ import type { HTMLAttributes } from 'react';
|
||||
import { replaceOrDefault } from '@/layouts/shared';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getLinks, type BaseLayoutProps } from './shared';
|
||||
|
||||
declare const { Nav, NavProvider }: typeof import('./home.client');
|
||||
import { Nav, NavProvider } from '@/layouts/home.client';
|
||||
|
||||
export type HomeLayoutProps = BaseLayoutProps & HTMLAttributes<HTMLElement>;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import Link from 'fumadocs-core/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import { Fragment, type ReactNode } from 'react';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import Link from 'fumadocs-core/link';
|
||||
|
||||
+10
-12
@@ -12,10 +12,9 @@ import { Card, Cards } from '@/components/card';
|
||||
import { Callout } from '@/components/callout';
|
||||
import { Heading } from '@/components/heading';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { Pre } from '@/mdx.client';
|
||||
|
||||
declare const { Pre }: typeof import('./mdx.client');
|
||||
|
||||
function Image(props: ImgHTMLAttributes<HTMLImageElement>): React.ReactElement {
|
||||
function Image(props: ImgHTMLAttributes<HTMLImageElement>) {
|
||||
return (
|
||||
<NextImage
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 70vw, 900px"
|
||||
@@ -25,9 +24,7 @@ function Image(props: ImgHTMLAttributes<HTMLImageElement>): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
function Table(
|
||||
props: TableHTMLAttributes<HTMLTableElement>,
|
||||
): React.ReactElement {
|
||||
function Table(props: TableHTMLAttributes<HTMLTableElement>) {
|
||||
return (
|
||||
<div className="relative overflow-auto">
|
||||
<table {...props} />
|
||||
@@ -41,22 +38,22 @@ const defaultMdxComponents = {
|
||||
Cards,
|
||||
a: Link as FC<AnchorHTMLAttributes<HTMLAnchorElement>>,
|
||||
img: Image,
|
||||
h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h1: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h1" {...props} />
|
||||
),
|
||||
h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h2: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h2" {...props} />
|
||||
),
|
||||
h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h3: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h3" {...props} />
|
||||
),
|
||||
h4: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h4: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h4" {...props} />
|
||||
),
|
||||
h5: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h5: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h5" {...props} />
|
||||
),
|
||||
h6: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||
h6: (props: HTMLAttributes<HTMLHeadingElement>) => (
|
||||
<Heading as="h6" {...props} />
|
||||
),
|
||||
table: Table,
|
||||
@@ -74,6 +71,7 @@ const defaultMdxComponents = {
|
||||
*
|
||||
* @param c - MDX Components
|
||||
* @returns MDX Components with re-created client components
|
||||
* @deprecated no longer used
|
||||
*/
|
||||
export function createComponents<
|
||||
Components extends Record<string, FC<unknown>>,
|
||||
|
||||
+11
-14
@@ -7,16 +7,17 @@ import { Card, Cards } from '@/components/card';
|
||||
import type { EditOnGitHubOptions } from '@/components/layout/edit-on-github';
|
||||
import { replaceOrDefault } from '@/layouts/shared';
|
||||
import { cn } from './utils/cn';
|
||||
import type { BreadcrumbProps, FooterProps, TOCProps } from './page.client';
|
||||
|
||||
declare const {
|
||||
Toc,
|
||||
TocPopover,
|
||||
import {
|
||||
Breadcrumb,
|
||||
type BreadcrumbProps,
|
||||
Footer,
|
||||
TOCItems,
|
||||
type FooterProps,
|
||||
LastUpdate,
|
||||
}: typeof import('./page.client');
|
||||
Toc,
|
||||
TOCItems,
|
||||
TocPopover,
|
||||
type TOCProps,
|
||||
} from './page.client';
|
||||
|
||||
const ClerkTOCItems = dynamic(() => import('@/components/layout/toc-clerk'));
|
||||
const EditOnGitHub = dynamic(
|
||||
@@ -92,7 +93,7 @@ export function DocsPage({
|
||||
...tocOptions
|
||||
} = {},
|
||||
...props
|
||||
}: DocsPageProps): React.ReactElement {
|
||||
}: DocsPageProps): ReactNode {
|
||||
return (
|
||||
<AnchorProvider toc={toc} single={tocOptions.single}>
|
||||
<div
|
||||
@@ -237,7 +238,7 @@ export function DocsCategory({
|
||||
page: Page;
|
||||
from: LoaderOutput<LoaderConfig>;
|
||||
tree?: PageTree.Root;
|
||||
}): React.ReactNode {
|
||||
}): ReactNode {
|
||||
const tree =
|
||||
forcedTree ??
|
||||
(from._i18n
|
||||
@@ -277,11 +278,7 @@ DocsBody.displayName = 'DocsBody';
|
||||
/**
|
||||
* For separate MDX page
|
||||
*/
|
||||
export function withArticle({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}): React.ReactElement {
|
||||
export function withArticle({ children }: { children: ReactNode }): ReactNode {
|
||||
return (
|
||||
<main className="container py-12">
|
||||
<article className="prose">{children}</article>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
import {
|
||||
useState,
|
||||
useRef,
|
||||
@@ -11,15 +12,17 @@ export function useCopyButton(
|
||||
): [checked: boolean, onClick: MouseEventHandler] {
|
||||
const [checked, setChecked] = useState(false);
|
||||
const timeoutRef = useRef<number | null>(null);
|
||||
const callbackRef = useRef(onCopy);
|
||||
callbackRef.current = onCopy;
|
||||
|
||||
const onClick: MouseEventHandler = useCallback(() => {
|
||||
if (timeoutRef.current) window.clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
setChecked(false);
|
||||
}, 1500);
|
||||
onCopy();
|
||||
callbackRef.current();
|
||||
setChecked(true);
|
||||
}, [onCopy]);
|
||||
}, []);
|
||||
|
||||
// Avoid updates after being unmounted
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["./src/**/*"]
|
||||
}
|
||||
@@ -5,5 +5,5 @@
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
Generated
+45
-3
@@ -1113,6 +1113,9 @@ importers:
|
||||
fumadocs-core:
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
lucide-react:
|
||||
specifier: ^0.454.0
|
||||
version: 0.454.0([email protected])
|
||||
next-themes:
|
||||
specifier: ^0.3.0
|
||||
version: 0.3.0([email protected]([email protected]))([email protected])
|
||||
@@ -1144,9 +1147,6 @@ importers:
|
||||
eslint-config-custom:
|
||||
specifier: workspace:*
|
||||
version: link:../eslint-config-custom
|
||||
lucide-react:
|
||||
specifier: ^0.454.0
|
||||
version: 0.454.0([email protected])
|
||||
next:
|
||||
specifier: 15.0.2
|
||||
version: 15.0.2([email protected]([email protected]))([email protected])
|
||||
@@ -1162,6 +1162,9 @@ importers:
|
||||
tailwindcss:
|
||||
specifier: ^3.4.13
|
||||
version: 3.4.14
|
||||
tsc-alias:
|
||||
specifier: ^1.8.10
|
||||
version: 1.8.10
|
||||
tsconfig:
|
||||
specifier: workspace:*
|
||||
version: link:../tsconfig
|
||||
@@ -3416,6 +3419,10 @@ packages:
|
||||
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
|
||||
engines: {node: ^12.20.0 || >=14}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
|
||||
|
||||
@@ -4704,6 +4711,10 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
@@ -4983,6 +4994,10 @@ packages:
|
||||
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -5128,6 +5143,10 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
@@ -5697,6 +5716,10 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==}
|
||||
hasBin: true
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||
|
||||
@@ -8365,6 +8388,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
@@ -10152,6 +10177,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
@@ -10415,6 +10442,10 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
queue-lit: 1.5.2
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
@@ -10540,6 +10571,8 @@ snapshots:
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected]:
|
||||
@@ -11253,6 +11286,15 @@ snapshots:
|
||||
'@ts-morph/common': 0.25.0
|
||||
code-block-writer: 13.0.3
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
commander: 9.5.0
|
||||
globby: 11.1.0
|
||||
mylas: 2.1.13
|
||||
normalize-path: 3.0.0
|
||||
plimit-lit: 1.6.1
|
||||
|
||||
[email protected]: {}
|
||||
|
||||
[email protected](@swc/[email protected](@swc/[email protected]))([email protected])([email protected])([email protected])([email protected])([email protected]):
|
||||
|
||||
Reference in New Issue
Block a user