diff --git a/apps/docs/features/docs/MdxBase.tsx b/apps/docs/features/docs/MdxBase.tsx index ba2d15b3a5..0123fb2410 100644 --- a/apps/docs/features/docs/MdxBase.tsx +++ b/apps/docs/features/docs/MdxBase.tsx @@ -3,14 +3,13 @@ import { components } from '~/features/docs/MdxBase.shared' import { guidesData } from '~/lib/guidesData' import { SerializeOptions } from '~/types/next-mdx-remote-serialize' import { isFeatureEnabled } from 'common' -import { MDXRemote } from 'next-mdx-remote/rsc' +import { MDXRemote } from 'next-mdx-remote-client/rsc' import { type ComponentProps } from 'react' import rehypeKatex from 'rehype-katex' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' const mdxOptions: SerializeOptions = { - blockJS: false, mdxOptions: { remarkPlugins: [[remarkMath, { singleDollarTextMath: false }], remarkGfm], rehypePlugins: [rehypeKatex as any], diff --git a/apps/docs/lib/docs.ts b/apps/docs/lib/docs.ts index 3e8ea84a74..bfd0b1e426 100644 --- a/apps/docs/lib/docs.ts +++ b/apps/docs/lib/docs.ts @@ -1,12 +1,12 @@ -import matter from 'gray-matter' -import { serialize } from 'next-mdx-remote/serialize' import { existsSync } from 'node:fs' import { readdir, readFile } from 'node:fs/promises' import { basename, extname, join, sep } from 'node:path' +import { type SerializeOptions } from '~/types/next-mdx-remote-serialize' +import matter from 'gray-matter' +import { serialize } from 'next-mdx-remote-client/serialize' import rehypeKatex from 'rehype-katex' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' -import { type SerializeOptions } from '~/types/next-mdx-remote-serialize' // MUST be process.cwd() here, not import.meta.url, or files that are added // with outputFileTracingIncludes (not auto-traced) will not be found at @@ -125,14 +125,13 @@ export async function getGuidesStaticProps( return } - const mdxOptions: SerializeOptions = { - blockJS: false, + const options: SerializeOptions = { mdxOptions: { remarkPlugins: [[remarkMath, { singleDollarTextMath: false }], remarkGfm], rehypePlugins: [rehypeKatex as any], }, } - const mdxSource = await serialize(content, mdxOptions) + const mdxSource = await serialize({ source: content, options: options }) return { props: { diff --git a/apps/docs/lib/mdx/generateRefMarkdown.tsx b/apps/docs/lib/mdx/generateRefMarkdown.tsx index bd3b03fb4c..7f9c750b6b 100644 --- a/apps/docs/lib/mdx/generateRefMarkdown.tsx +++ b/apps/docs/lib/mdx/generateRefMarkdown.tsx @@ -1,10 +1,9 @@ import fs from 'fs' - +import type { ICommonMarkdown } from '~/components/reference/Reference.types' import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' } import matter from 'gray-matter' -import { serialize } from 'next-mdx-remote/serialize' +import { serialize } from 'next-mdx-remote-client/serialize' import remarkGfm from 'remark-gfm' -import type { ICommonMarkdown } from '~/components/reference/Reference.types' async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) { let markdownContent: any[] = [] @@ -39,12 +38,14 @@ async function generateRefMarkdown(sections: ICommonMarkdown[], slug: string) { meta: data, // introPage: introPages.includes(x), content: content - ? await serialize(content ?? '', { - blockJS: false, - // MDX's available options, see the MDX docs for more info. - // https://mdxjs.com/packages/mdx/#compilefile-options - mdxOptions: { - remarkPlugins: [remarkGfm], + ? await serialize({ + source: content ?? '', + options: { + // MDX's available options, see the MDX docs for more info. + // https://mdxjs.com/packages/mdx/#compilefile-options + mdxOptions: { + remarkPlugins: [remarkGfm], + }, }, }) : null, diff --git a/apps/docs/package.json b/apps/docs/package.json index 1259814500..3e0ce1133a 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -91,7 +91,7 @@ "micromark-extension-gfm": "^2.0.3", "micromark-extension-mdxjs": "^1.0.0", "next": "^15.5.15", - "next-mdx-remote": "^6.0.0", + "next-mdx-remote-client": "^1.1.7", "next-plugin-yaml": "^1.0.1", "next-themes": "catalog:", "nuqs": "^1.19.1", diff --git a/apps/docs/types/next-mdx-remote-serialize.ts b/apps/docs/types/next-mdx-remote-serialize.ts index 4e5c0711d6..77f6afc883 100644 --- a/apps/docs/types/next-mdx-remote-serialize.ts +++ b/apps/docs/types/next-mdx-remote-serialize.ts @@ -1,5 +1,5 @@ -import { serialize } from 'next-mdx-remote/serialize' +import { SerializeOptions as NextMdxRemoteSerializeOptions } from 'next-mdx-remote-client/serialize' // The SerializeOptions is not exported from next-mdx-remote/serialize, so we need to // manually define it here. -export type SerializeOptions = Parameters[1] +export type SerializeOptions = NextMdxRemoteSerializeOptions diff --git a/apps/ui-library/public/r/dropzone-nextjs.json b/apps/ui-library/public/r/dropzone-nextjs.json index 9bbfcb1427..a7db28470b 100644 --- a/apps/ui-library/public/r/dropzone-nextjs.json +++ b/apps/ui-library/public/r/dropzone-nextjs.json @@ -16,7 +16,7 @@ "files": [ { "path": "registry/default/blocks/dropzone/components/dropzone.tsx", - "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", + "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/dropzone-react-router.json b/apps/ui-library/public/r/dropzone-react-router.json index 20ceefaef3..55ae71c48b 100644 --- a/apps/ui-library/public/r/dropzone-react-router.json +++ b/apps/ui-library/public/r/dropzone-react-router.json @@ -16,7 +16,7 @@ "files": [ { "path": "registry/default/blocks/dropzone/components/dropzone.tsx", - "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", + "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/dropzone-react.json b/apps/ui-library/public/r/dropzone-react.json index 29c18c95cd..5005e769cc 100644 --- a/apps/ui-library/public/r/dropzone-react.json +++ b/apps/ui-library/public/r/dropzone-react.json @@ -15,7 +15,7 @@ "files": [ { "path": "registry/default/blocks/dropzone/components/dropzone.tsx", - "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", + "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/dropzone-tanstack.json b/apps/ui-library/public/r/dropzone-tanstack.json index 470f6adf54..a58c4f1d9f 100644 --- a/apps/ui-library/public/r/dropzone-tanstack.json +++ b/apps/ui-library/public/r/dropzone-tanstack.json @@ -16,7 +16,7 @@ "files": [ { "path": "registry/default/blocks/dropzone/components/dropzone.tsx", - "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", + "content": "'use client'\n\nimport { CheckCircle, File, Loader2, Upload, X } from 'lucide-react'\nimport { createContext, useCallback, useContext, type PropsWithChildren } from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { type UseSupabaseUploadReturn } from '@/registry/default/blocks/dropzone/hooks/use-supabase-upload'\nimport { Button } from '@/registry/default/components/ui/button'\n\nexport const formatBytes = (\n bytes: number,\n decimals = 2,\n size?: 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' | 'EB' | 'ZB' | 'YB'\n) => {\n const k = 1000\n const dm = decimals < 0 ? 0 : decimals\n const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\n if (bytes === 0 || bytes === undefined) return size !== undefined ? `0 ${size}` : '0 bytes'\n const i = size !== undefined ? sizes.indexOf(size) : Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]\n}\n\ntype DropzoneContextType = Omit\n\nconst DropzoneContext = createContext(undefined)\n\ntype DropzoneProps = UseSupabaseUploadReturn & {\n className?: string\n}\n\nconst Dropzone = ({\n className,\n children,\n getRootProps,\n getInputProps,\n ...restProps\n}: PropsWithChildren) => {\n const isSuccess = restProps.isSuccess\n const isActive = restProps.isDragActive\n const isInvalid =\n (restProps.isDragActive && restProps.isDragReject) ||\n (restProps.errors.length > 0 && !restProps.isSuccess) ||\n restProps.files.some((file) => file.errors.length !== 0)\n\n return (\n \n \n \n {children}\n \n \n )\n}\nconst DropzoneContent = ({ className }: { className?: string }) => {\n const {\n files,\n setFiles,\n onUpload,\n loading,\n successes,\n errors,\n maxFileSize,\n maxFiles,\n isSuccess,\n } = useDropzoneContext()\n\n const exceedMaxFiles = files.length > maxFiles\n\n const handleRemoveFile = useCallback(\n (fileName: string) => {\n setFiles(files.filter((file) => file.name !== fileName))\n },\n [files, setFiles]\n )\n\n if (isSuccess) {\n return (\n
\n \n

\n Successfully uploaded {files.length} file{files.length > 1 ? 's' : ''}\n

\n
\n )\n }\n\n return (\n
\n {files.map((file, idx) => {\n const fileError = errors.find((e) => e.name === file.name)\n const isSuccessfullyUploaded = !!successes.find((e) => e === file.name)\n\n return (\n \n {file.type.startsWith('image/') ? (\n
\n {file.name}\n
\n ) : (\n
\n \n
\n )}\n\n
\n

\n {file.name}\n

\n {file.errors.length > 0 ? (\n

\n {file.errors\n .map((e) =>\n e.message.startsWith('File is larger than')\n ? `File is larger than ${formatBytes(maxFileSize, 2)} (Size: ${formatBytes(file.size, 2)})`\n : e.message\n )\n .join(', ')}\n

\n ) : loading && !isSuccessfullyUploaded ? (\n

Uploading file...

\n ) : !!fileError ? (\n

Failed to upload: {fileError.message}

\n ) : isSuccessfullyUploaded ? (\n

Successfully uploaded file

\n ) : (\n

{formatBytes(file.size, 2)}

\n )}\n
\n\n {!loading && !isSuccessfullyUploaded && (\n handleRemoveFile(file.name)}\n >\n \n \n )}\n
\n )\n })}\n {exceedMaxFiles && (\n

\n You may upload only up to {maxFiles} files, please remove {files.length - maxFiles} file\n {files.length - maxFiles > 1 ? 's' : ''}.\n

\n )}\n {files.length > 0 && !exceedMaxFiles && (\n
\n file.errors.length !== 0) || loading}\n >\n {loading ? (\n <>\n \n Uploading...\n \n ) : (\n <>Upload files\n )}\n \n
\n )}\n \n )\n}\n\nconst DropzoneEmptyState = ({ className }: { className?: string }) => {\n const { maxFiles, maxFileSize, inputRef, isSuccess } = useDropzoneContext()\n\n if (isSuccess) {\n return null\n }\n\n return (\n
\n \n

\n Upload{!!maxFiles && maxFiles > 1 ? ` ${maxFiles}` : ''} file\n {!maxFiles || maxFiles > 1 ? 's' : ''}\n

\n
\n

\n Drag and drop or{' '}\n inputRef.current?.click()}\n className=\"underline cursor-pointer transition hover:text-foreground\"\n >\n select {maxFiles === 1 ? `file` : 'files'}\n {' '}\n to upload\n

\n {maxFileSize !== Number.POSITIVE_INFINITY && (\n

\n Maximum file size: {formatBytes(maxFileSize, 2)}\n

\n )}\n
\n
\n )\n}\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext)\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone')\n }\n\n return context\n}\n\nexport { Dropzone, DropzoneContent, DropzoneEmptyState, useDropzoneContext }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/platform-kit-nextjs.json b/apps/ui-library/public/r/platform-kit-nextjs.json index 6360b21ca9..3cb976b10c 100644 --- a/apps/ui-library/public/r/platform-kit-nextjs.json +++ b/apps/ui-library/public/r/platform-kit-nextjs.json @@ -66,7 +66,7 @@ }, { "path": "registry/default/platform/platform-kit-nextjs/components/results-table.tsx", - "content": "'use client'\n\nimport { cn } from '@/lib/utils'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/registry/default/components/ui/table'\n\ninterface ResultsTableProps {\n data: any[]\n onRowClick?: (row: any) => void\n}\n\nexport function ResultsTable({ data, onRowClick }: ResultsTableProps) {\n if (!data || data.length === 0) {\n return

The query returned no results.

\n }\n\n const headers = Object.keys(data[0])\n\n return (\n
\n \n \n \n {headers.map((header) => (\n \n {header}\n \n ))}\n \n \n \n {data.map((row, rowIndex) => (\n onRowClick?.(row)}\n className={cn(onRowClick && 'cursor-pointer hover:bg-muted/50 group')}\n >\n {headers.map((header) => (\n \n
\n {JSON.stringify(row[header]).replace(/^\"|\"$/g, '')}\n
\n \n ))}\n \n ))}\n
\n
\n
\n )\n}\n", + "content": "'use client'\n\nimport { cn } from '@/lib/utils'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/registry/default/components/ui/table'\n\ninterface ResultsTableProps {\n data: any[]\n onRowClick?: (row: any) => void\n}\n\nexport function ResultsTable({ data, onRowClick }: ResultsTableProps) {\n if (!data || data.length === 0) {\n return

The query returned no results.

\n }\n\n const headers = Object.keys(data[0])\n\n return (\n
\n \n \n \n {headers.map((header) => (\n \n {header}\n \n ))}\n \n \n \n {data.map((row, rowIndex) => (\n onRowClick?.(row)}\n className={cn(onRowClick && 'cursor-pointer hover:bg-muted/50 group')}\n >\n {headers.map((header) => (\n \n
\n {JSON.stringify(row[header]).replace(/^\"|\"$/g, '')}\n
\n \n ))}\n \n ))}\n
\n
\n
\n )\n}\n", "type": "registry:component" }, { @@ -91,7 +91,7 @@ }, { "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/logs.tsx", - "content": "'use client'\n\nimport { Check, ChevronsUpDown, Logs, Terminal } from 'lucide-react'\nimport { useMemo, useState } from 'react'\n\nimport { genDefaultQuery, LogsTableName } from '../../lib/logs'\nimport { cn } from '@/lib/utils'\nimport { Alert, AlertDescription, AlertTitle } from '@/registry/default/components/ui/alert'\nimport { Button } from '@/registry/default/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/components/ui/command'\nimport {\n HoverCard,\n HoverCardContent,\n HoverCardTrigger,\n} from '@/registry/default/components/ui/hover-card'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/components/ui/popover'\nimport { Skeleton } from '@/registry/default/components/ui/skeleton'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/registry/default/components/ui/table'\nimport { useGetLogs } from '@/registry/default/platform/platform-kit-nextjs/hooks/use-logs'\n\n// Define log types with names and descriptions\nconst logTypes = [\n {\n value: LogsTableName.FN_EDGE,\n label: 'Function Edge Logs',\n description: 'Edge function execution logs with request and response metadata',\n },\n {\n value: LogsTableName.AUTH,\n label: 'Authentication Logs',\n description: 'User authentication events and security logs',\n },\n {\n value: LogsTableName.POSTGRES,\n label: 'PostgreSQL Logs',\n description: 'Database queries, errors, and performance metrics',\n },\n {\n value: LogsTableName.REALTIME,\n label: 'Realtime Logs',\n description: 'WebSocket connections and realtime subscriptions',\n },\n {\n value: LogsTableName.STORAGE,\n label: 'Storage Logs',\n description: 'File uploads, downloads, and storage operations',\n },\n {\n value: LogsTableName.PG_CRON,\n label: 'Cron Job Logs',\n description: 'Scheduled job executions and cron task logs',\n },\n {\n value: LogsTableName.EDGE,\n label: 'Edge Logs',\n description: 'HTTP requests and responses from the data API',\n },\n\n {\n value: LogsTableName.FUNCTIONS,\n label: 'Function Logs',\n description: 'Serverless function execution logs and events',\n },\n {\n value: LogsTableName.POSTGREST,\n label: 'PostgREST Logs',\n description: 'API requests to your database through PostgREST',\n },\n {\n value: LogsTableName.SUPAVISOR,\n label: 'Supavisor Logs',\n description: 'Connection pooling and database proxy logs',\n },\n {\n value: LogsTableName.PGBOUNCER,\n label: 'PgBouncer Logs',\n description: 'Legacy connection pooling logs',\n },\n {\n value: LogsTableName.PG_UPGRADE,\n label: 'PostgreSQL Upgrade Logs',\n description: 'Database upgrade processes and migration logs',\n },\n]\n\nexport function LogsManager({ projectRef }: { projectRef: string }) {\n const [activeTab, setActiveTab] = useState(LogsTableName.FN_EDGE)\n const [open, setOpen] = useState(false)\n\n const sql = useMemo(() => genDefaultQuery(activeTab), [activeTab])\n\n const { data: logs, isLoading, error } = useGetLogs(projectRef, { sql })\n\n const selectedLogType = logTypes.find((type) => type.value === activeTab)\n\n return (\n <>\n
\n
\n

Logs

\n

\n Debug errors and track activity in your app\n

\n
\n \n \n \n {selectedLogType ? selectedLogType.label : 'Select log type...'}\n \n \n \n \n \n \n {\n e.stopPropagation()\n }}\n style={{ overscrollBehavior: 'contain' }}\n >\n No log type found.\n \n {logTypes.map((logType) => (\n {\n setActiveTab(currentValue as LogsTableName)\n setOpen(false)\n }}\n className=\"flex items-center gap-2 p-3\"\n >\n
\n
{logType.label}
\n
\n {logType.description}\n
\n
\n \n \n ))}\n
\n \n
\n
\n
\n
\n\n {isLoading && (\n
\n \n \n \n \n
\n )}\n {(error || (logs && logs.error)) && (\n
\n \n \n Error fetching logs\n \n {(error as any)?.message ||\n (typeof logs?.error === 'object' && logs.error?.message) ||\n 'An unexpected error occurred. Please try again.'}\n \n \n
\n )}\n {logs && logs.result && logs.result.length > 0 && (\n
\n \n \n \n {Object.keys(logs.result[0] as object).map((key, idx, arr) => (\n \n {key.replace(/_/g, ' ').replace(/\\b\\w/g, (l) => l.toUpperCase())}\n \n ))}\n \n \n \n {(logs.result as any[]).map((log, index) => (\n \n {Object.keys(logs.result?.[0] ?? []).map((key, idx, arr) => {\n const value = log[key]\n const formattedValue = (() => {\n if (key === 'timestamp' && typeof value === 'number') {\n return new Date(value / 1000).toLocaleString()\n }\n if (value === null) {\n return 'NULL'\n }\n return typeof value === 'object'\n ? JSON.stringify(value, null, 2)\n : String(value)\n })()\n\n return (\n \n \n \n
\n {formattedValue}\n
\n
\n \n
\n                              {formattedValue}\n                            
\n
\n
\n \n )\n })}\n
\n ))}\n
\n
\n
\n )}\n {logs && logs.result && logs.result.length === 0 && (\n
\n \n \n No logs found\n \n Logs will appear here when your application generates activity.\n \n \n
\n )}\n \n )\n}\n", + "content": "'use client'\n\nimport { Check, ChevronsUpDown, Logs, Terminal } from 'lucide-react'\nimport { useMemo, useState } from 'react'\n\nimport { genDefaultQuery, LogsTableName } from '../../lib/logs'\nimport { cn } from '@/lib/utils'\nimport { Alert, AlertDescription, AlertTitle } from '@/registry/default/components/ui/alert'\nimport { Button } from '@/registry/default/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/registry/default/components/ui/command'\nimport {\n HoverCard,\n HoverCardContent,\n HoverCardTrigger,\n} from '@/registry/default/components/ui/hover-card'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/registry/default/components/ui/popover'\nimport { Skeleton } from '@/registry/default/components/ui/skeleton'\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/registry/default/components/ui/table'\nimport { useGetLogs } from '@/registry/default/platform/platform-kit-nextjs/hooks/use-logs'\n\n// Define log types with names and descriptions\nconst logTypes = [\n {\n value: LogsTableName.FN_EDGE,\n label: 'Function Edge Logs',\n description: 'Edge function execution logs with request and response metadata',\n },\n {\n value: LogsTableName.AUTH,\n label: 'Authentication Logs',\n description: 'User authentication events and security logs',\n },\n {\n value: LogsTableName.POSTGRES,\n label: 'PostgreSQL Logs',\n description: 'Database queries, errors, and performance metrics',\n },\n {\n value: LogsTableName.REALTIME,\n label: 'Realtime Logs',\n description: 'WebSocket connections and realtime subscriptions',\n },\n {\n value: LogsTableName.STORAGE,\n label: 'Storage Logs',\n description: 'File uploads, downloads, and storage operations',\n },\n {\n value: LogsTableName.PG_CRON,\n label: 'Cron Job Logs',\n description: 'Scheduled job executions and cron task logs',\n },\n {\n value: LogsTableName.EDGE,\n label: 'Edge Logs',\n description: 'HTTP requests and responses from the data API',\n },\n\n {\n value: LogsTableName.FUNCTIONS,\n label: 'Function Logs',\n description: 'Serverless function execution logs and events',\n },\n {\n value: LogsTableName.POSTGREST,\n label: 'PostgREST Logs',\n description: 'API requests to your database through PostgREST',\n },\n {\n value: LogsTableName.SUPAVISOR,\n label: 'Supavisor Logs',\n description: 'Connection pooling and database proxy logs',\n },\n {\n value: LogsTableName.PGBOUNCER,\n label: 'PgBouncer Logs',\n description: 'Legacy connection pooling logs',\n },\n {\n value: LogsTableName.PG_UPGRADE,\n label: 'PostgreSQL Upgrade Logs',\n description: 'Database upgrade processes and migration logs',\n },\n]\n\nexport function LogsManager({ projectRef }: { projectRef: string }) {\n const [activeTab, setActiveTab] = useState(LogsTableName.FN_EDGE)\n const [open, setOpen] = useState(false)\n\n const sql = useMemo(() => genDefaultQuery(activeTab), [activeTab])\n\n const { data: logs, isLoading, error } = useGetLogs(projectRef, { sql })\n\n const selectedLogType = logTypes.find((type) => type.value === activeTab)\n\n return (\n <>\n
\n
\n

Logs

\n

\n Debug errors and track activity in your app\n

\n
\n \n \n \n {selectedLogType ? selectedLogType.label : 'Select log type...'}\n \n \n \n \n \n \n {\n e.stopPropagation()\n }}\n style={{ overscrollBehavior: 'contain' }}\n >\n No log type found.\n \n {logTypes.map((logType) => (\n {\n setActiveTab(currentValue as LogsTableName)\n setOpen(false)\n }}\n className=\"flex items-center gap-2 p-3\"\n >\n
\n
{logType.label}
\n
\n {logType.description}\n
\n
\n \n \n ))}\n
\n \n
\n
\n
\n
\n\n {isLoading && (\n
\n \n \n \n \n
\n )}\n {(error || (logs && logs.error)) && (\n
\n \n \n Error fetching logs\n \n {(error as any)?.message ||\n (typeof logs?.error === 'object' && logs.error?.message) ||\n 'An unexpected error occurred. Please try again.'}\n \n \n
\n )}\n {logs && logs.result && logs.result.length > 0 && (\n
\n \n \n \n {Object.keys(logs.result[0] as object).map((key, idx, arr) => (\n \n {key.replace(/_/g, ' ').replace(/\\b\\w/g, (l) => l.toUpperCase())}\n \n ))}\n \n \n \n {(logs.result as any[]).map((log, index) => (\n \n {Object.keys(logs.result?.[0] ?? []).map((key, idx, arr) => {\n const value = log[key]\n const formattedValue = (() => {\n if (key === 'timestamp' && typeof value === 'number') {\n return new Date(value / 1000).toLocaleString()\n }\n if (value === null) {\n return 'NULL'\n }\n return typeof value === 'object'\n ? JSON.stringify(value, null, 2)\n : String(value)\n })()\n\n return (\n \n \n \n
\n {formattedValue}\n
\n
\n \n
\n                              {formattedValue}\n                            
\n
\n
\n \n )\n })}\n
\n ))}\n
\n
\n
\n )}\n {logs && logs.result && logs.result.length === 0 && (\n
\n \n \n No logs found\n \n Logs will appear here when your application generates activity.\n \n \n
\n )}\n \n )\n}\n", "type": "registry:component" }, { @@ -106,7 +106,7 @@ }, { "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/suggestions.tsx", - "content": "'use client'\n\nimport { Terminal } from 'lucide-react'\nimport { useMemo } from 'react'\nimport ReactMarkdown from 'react-markdown'\n\nimport { Alert, AlertDescription, AlertTitle } from '@/registry/default/components/ui/alert'\nimport { Badge } from '@/registry/default/components/ui/badge'\nimport { Skeleton } from '@/registry/default/components/ui/skeleton'\nimport { useGetSuggestions } from '@/registry/default/platform/platform-kit-nextjs/hooks/use-suggestions'\n\nexport function SuggestionsManager({ projectRef }: { projectRef: string }) {\n const { data: suggestions, isLoading, error } = useGetSuggestions(projectRef)\n\n const sortedSuggestions = useMemo(() => {\n if (!suggestions) return []\n const levelOrder = { ERROR: 1, WARN: 2, INFO: 3 }\n return [...suggestions].sort((a: any, b: any) => {\n const levelA = levelOrder[a.level as keyof typeof levelOrder] || 99\n const levelB = levelOrder[b.level as keyof typeof levelOrder] || 99\n return levelA - levelB\n })\n }, [suggestions])\n\n const getBadgeVariant = (level: 'ERROR' | 'WARN' | 'INFO') => {\n switch (level) {\n case 'ERROR':\n return 'destructive'\n case 'WARN':\n return 'secondary'\n default:\n return 'outline'\n }\n }\n\n return (\n
\n

Suggestions

\n

\n Improve your project's security and performance.\n

\n {isLoading && (\n
\n \n \n \n \n
\n )}\n {error && (\n \n \n Error fetching suggestions\n \n {(error as any)?.message || 'An unexpected error occurred. Please try again.'}\n \n \n )}\n {suggestions && (\n
\n {sortedSuggestions.length > 0 ? (\n
\n {sortedSuggestions.map((suggestion: any) => (\n \n
\n
\n

{suggestion.title}

\n
\n \n {suggestion.level}\n \n {suggestion.type && (\n \n {suggestion.type.charAt(0).toUpperCase() + suggestion.type.slice(1)}\n \n )}\n
\n
\n
\n \n {children}\n \n ) : (\n
\n                                {children}\n                              
\n )\n },\n }}\n >\n {suggestion.detail}\n \n
\n
\n
\n ))}\n
\n ) : (\n \n \n No suggestions found\n \n Your project looks good! No suggestions at this time.\n \n \n )}\n
\n )}\n \n )\n}\n", + "content": "'use client'\n\nimport { Terminal } from 'lucide-react'\nimport { useMemo } from 'react'\nimport ReactMarkdown from 'react-markdown'\n\nimport { Alert, AlertDescription, AlertTitle } from '@/registry/default/components/ui/alert'\nimport { Badge } from '@/registry/default/components/ui/badge'\nimport { Skeleton } from '@/registry/default/components/ui/skeleton'\nimport { useGetSuggestions } from '@/registry/default/platform/platform-kit-nextjs/hooks/use-suggestions'\n\nexport function SuggestionsManager({ projectRef }: { projectRef: string }) {\n const { data: suggestions, isLoading, error } = useGetSuggestions(projectRef)\n\n const sortedSuggestions = useMemo(() => {\n if (!suggestions) return []\n const levelOrder = { ERROR: 1, WARN: 2, INFO: 3 }\n return [...suggestions].sort((a: any, b: any) => {\n const levelA = levelOrder[a.level as keyof typeof levelOrder] || 99\n const levelB = levelOrder[b.level as keyof typeof levelOrder] || 99\n return levelA - levelB\n })\n }, [suggestions])\n\n const getBadgeVariant = (level: 'ERROR' | 'WARN' | 'INFO') => {\n switch (level) {\n case 'ERROR':\n return 'destructive'\n case 'WARN':\n return 'secondary'\n default:\n return 'outline'\n }\n }\n\n return (\n
\n

Suggestions

\n

\n Improve your project's security and performance.\n

\n {isLoading && (\n
\n \n \n \n \n
\n )}\n {error && (\n \n \n Error fetching suggestions\n \n {(error as any)?.message || 'An unexpected error occurred. Please try again.'}\n \n \n )}\n {suggestions && (\n
\n {sortedSuggestions.length > 0 ? (\n
\n {sortedSuggestions.map((suggestion: any) => (\n \n
\n
\n

{suggestion.title}

\n
\n \n {suggestion.level}\n \n {suggestion.type && (\n \n {suggestion.type.charAt(0).toUpperCase() + suggestion.type.slice(1)}\n \n )}\n
\n
\n
\n \n {children}\n \n ) : (\n
\n                                {children}\n                              
\n )\n },\n }}\n >\n {suggestion.detail}\n \n
\n
\n
\n ))}\n
\n ) : (\n \n \n No suggestions found\n \n Your project looks good! No suggestions at this time.\n \n \n )}\n
\n )}\n \n )\n}\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-avatar-stack-nextjs.json b/apps/ui-library/public/r/realtime-avatar-stack-nextjs.json index f078aca1cc..dfbca00e99 100644 --- a/apps/ui-library/public/r/realtime-avatar-stack-nextjs.json +++ b/apps/ui-library/public/r/realtime-avatar-stack-nextjs.json @@ -15,7 +15,7 @@ "files": [ { "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx", - "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", + "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-avatar-stack-react-router.json b/apps/ui-library/public/r/realtime-avatar-stack-react-router.json index 15b7dcecd5..01a135c676 100644 --- a/apps/ui-library/public/r/realtime-avatar-stack-react-router.json +++ b/apps/ui-library/public/r/realtime-avatar-stack-react-router.json @@ -15,7 +15,7 @@ "files": [ { "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx", - "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", + "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-avatar-stack-react.json b/apps/ui-library/public/r/realtime-avatar-stack-react.json index b2f47e770a..31aaa2fc42 100644 --- a/apps/ui-library/public/r/realtime-avatar-stack-react.json +++ b/apps/ui-library/public/r/realtime-avatar-stack-react.json @@ -14,7 +14,7 @@ "files": [ { "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx", - "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", + "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-avatar-stack-tanstack.json b/apps/ui-library/public/r/realtime-avatar-stack-tanstack.json index 8ad09db14d..13c883dcb4 100644 --- a/apps/ui-library/public/r/realtime-avatar-stack-tanstack.json +++ b/apps/ui-library/public/r/realtime-avatar-stack-tanstack.json @@ -15,7 +15,7 @@ "files": [ { "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx", - "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", + "content": "import { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/registry/default/components/ui/avatar'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/components/ui/tooltip'\n\nconst avatarStackVariants = cva('flex -space-x-4 -space-y-4', {\n variants: {\n orientation: {\n vertical: 'flex-row',\n horizontal: 'flex-col',\n },\n },\n defaultVariants: {\n orientation: 'vertical',\n },\n})\n\nexport interface AvatarStackProps\n extends React.HTMLAttributes, VariantProps {\n avatars: { name: string; image: string }[]\n maxAvatarsAmount?: number\n}\n\nconst AvatarStack = ({\n className,\n orientation,\n avatars,\n maxAvatarsAmount = 3,\n ...props\n}: AvatarStackProps) => {\n const shownAvatars = avatars.slice(0, maxAvatarsAmount)\n const hiddenAvatars = avatars.slice(maxAvatarsAmount)\n\n return (\n \n {shownAvatars.map(({ name, image }, index) => (\n \n \n \n \n \n {name\n ?.split(' ')\n ?.map((word) => word[0])\n ?.join('')\n ?.toUpperCase()}\n \n \n \n \n

{name}

\n
\n
\n ))}\n\n {hiddenAvatars.length ? (\n \n \n \n +{avatars.length - shownAvatars.length}\n \n \n \n {hiddenAvatars.map(({ name }, index) => (\n

{name}

\n ))}\n
\n
\n ) : null}\n \n )\n}\n\nexport { AvatarStack, avatarStackVariants }\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-cursor-nextjs.json b/apps/ui-library/public/r/realtime-cursor-nextjs.json index e391316657..10d19899a2 100644 --- a/apps/ui-library/public/r/realtime-cursor-nextjs.json +++ b/apps/ui-library/public/r/realtime-cursor-nextjs.json @@ -13,7 +13,7 @@ "files": [ { "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx", - "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", + "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-cursor-react-router.json b/apps/ui-library/public/r/realtime-cursor-react-router.json index 9585ad66f3..9d9c134f77 100644 --- a/apps/ui-library/public/r/realtime-cursor-react-router.json +++ b/apps/ui-library/public/r/realtime-cursor-react-router.json @@ -13,7 +13,7 @@ "files": [ { "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx", - "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", + "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-cursor-react.json b/apps/ui-library/public/r/realtime-cursor-react.json index 52b98fe284..0dfa9f6336 100644 --- a/apps/ui-library/public/r/realtime-cursor-react.json +++ b/apps/ui-library/public/r/realtime-cursor-react.json @@ -12,7 +12,7 @@ "files": [ { "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx", - "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", + "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", "type": "registry:component" }, { diff --git a/apps/ui-library/public/r/realtime-cursor-tanstack.json b/apps/ui-library/public/r/realtime-cursor-tanstack.json index 8d092101aa..67f6c9274b 100644 --- a/apps/ui-library/public/r/realtime-cursor-tanstack.json +++ b/apps/ui-library/public/r/realtime-cursor-tanstack.json @@ -13,7 +13,7 @@ "files": [ { "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx", - "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", + "content": "import { MousePointer2 } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\n\nexport const Cursor = ({\n className,\n style,\n color,\n name,\n}: {\n className?: string\n style?: React.CSSProperties\n color: string\n name: string\n}) => {\n return (\n
\n \n\n \n {name}\n
\n \n )\n}\n", "type": "registry:component" }, { diff --git a/apps/www/.env.local.example b/apps/www/.env.local.example index 9300dad637..614342fc7f 100644 --- a/apps/www/.env.local.example +++ b/apps/www/.env.local.example @@ -9,7 +9,7 @@ NEXT_PUBLIC_DOCS_URL=http://localhost:3005 NEXT_PUBLIC_ENVIRONMENT=local NEXT_PUBLIC_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001 NEXT_PUBLIC_IS_PLATFORM=true -NEXT_PUBLIC_MISC_USE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9idWxkYW5ycHRsb2t0eGNmZnZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTg2MTQ2ODUsImV4cCI6MjAzNDE5MDY4NX0.NFt49g6DFkc1X5khCzN5p01iAVo2TMxlx88cY1V0E2M +NEXT_PUBLIC_MISC_USE_ANON_KEY=sb_publishable_t45SVhgymMJOuamUXzJzPQ_sY-tSoUr NEXT_PUBLIC_MISC_USE_URL=https://obuldanrptloktxcffvn.supabase.co NEXT_PUBLIC_POSTHOG_HOST=https://ph.supabase.green NEXT_PUBLIC_POSTHOG_KEY=your-posthog-key-here diff --git a/apps/www/layouts/comparison.tsx b/apps/www/layouts/comparison.tsx index 95fa69d0f1..e24567e492 100644 --- a/apps/www/layouts/comparison.tsx +++ b/apps/www/layouts/comparison.tsx @@ -1,13 +1,13 @@ -import authors from 'lib/authors.json' -import { MDXRemote } from 'next-mdx-remote' -import { NextSeo } from 'next-seo' -import Image from 'next/image' -import Link from 'next/link' -import React from 'react' import CTABanner from '~/components/CTABanner' import DefaultLayout from '~/components/Layouts/Default' import { getAbsoluteBlogSocialImage } from '~/lib/blog-images' import { generateReadingTime } from '~/lib/helpers' +import authors from 'lib/authors.json' +import { MDXClient } from 'next-mdx-remote-client/csr' +import { NextSeo } from 'next-seo' +import Image from 'next/image' +import Link from 'next/link' +import React from 'react' interface Props { components: React.ReactNode @@ -125,7 +125,7 @@ const LayoutComparison = ({ components, props }: Props) => {
{/* Content */}
- +
Share this article
diff --git a/apps/www/lib/mdx/mdxOptionsBlog.ts b/apps/www/lib/mdx/mdxOptionsBlog.ts index 6f666dc255..6591a78a99 100644 --- a/apps/www/lib/mdx/mdxOptionsBlog.ts +++ b/apps/www/lib/mdx/mdxOptionsBlog.ts @@ -1,6 +1,6 @@ import { remarkCodeHike, type CodeHikeConfig } from '@code-hike/mdx' import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' } -import type { MDXRemoteProps } from 'next-mdx-remote/rsc' +import type { SerializeOptions } from 'next-mdx-remote-client/serialize' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' @@ -12,7 +12,7 @@ const codeHikeOptions: CodeHikeConfig = { autoImport: false, } -type MdxOptions = NonNullable['mdxOptions']> +type MdxOptions = NonNullable export const mdxOptionsBlog: MdxOptions = { remarkPlugins: [remarkNormalizeHtmlImages, [remarkCodeHike, codeHikeOptions], remarkGfm], diff --git a/apps/www/lib/mdx/mdxSerialize.ts b/apps/www/lib/mdx/mdxSerialize.ts index fca81b806b..b577073dc4 100644 --- a/apps/www/lib/mdx/mdxSerialize.ts +++ b/apps/www/lib/mdx/mdxSerialize.ts @@ -1,7 +1,7 @@ import { remarkCodeHike, type CodeHikeConfig } from '@code-hike/mdx' import { preprocessMdxWithCodeTabs } from '~/components/CodeTabs' import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' } -import { serialize } from 'next-mdx-remote/serialize' +import { serialize } from 'next-mdx-remote-client/serialize' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' @@ -157,32 +157,34 @@ export async function mdxSerialize(source: string, options?: { tocDepth?: number const tocDepth = options?.tocDepth ?? 2 let collectedToc: TocItem[] = [] - const mdxSource = await serialize(preprocessedSource, { - blockJS: false, - scope: { - chCodeConfig: codeHikeOptions, - }, - mdxOptions: { - remarkPlugins: [ - remarkNormalizeHtmlImages, - [remarkCodeHike, codeHikeOptions], - remarkGfm, - // Collect headings into a simple TOC structure - () => { - const plugin = createRemarkCollectToc(tocDepth) - const transformer = (plugin as any)() - return (tree: any) => { - transformer(tree) - if (tree?.data?.__collectedToc) { - collectedToc = tree.data.__collectedToc as TocItem[] + const mdxSource = await serialize({ + source: preprocessedSource, + options: { + scope: { + toc: { content: '', json: collectedToc }, + }, + mdxOptions: { + remarkPlugins: [ + remarkNormalizeHtmlImages, + [remarkCodeHike, codeHikeOptions], + remarkGfm, + // Collect headings into a simple TOC structure + () => { + const plugin = createRemarkCollectToc(tocDepth) + const transformer = (plugin as any)() + return (tree: any) => { + transformer(tree) + if (tree?.data?.__collectedToc) { + collectedToc = tree.data.__collectedToc as TocItem[] + } } - } - }, - ], - rehypePlugins: [ - // @ts-ignore - rehypeSlug, // add IDs to any h1-h6 tag that doesn't have one, using a slug made from its text - ], + }, + ], + rehypePlugins: [ + // @ts-ignore + rehypeSlug, // add IDs to any h1-h6 tag that doesn't have one, using a slug made from its text + ], + }, }, }) diff --git a/apps/www/package.json b/apps/www/package.json index 6730c8ac2b..abc51b21f5 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -65,7 +65,7 @@ "micromark-extension-gfm": "^2.0.3", "micromark-extension-mdxjs": "^1.0.1", "next": "^15.5.15", - "next-mdx-remote": "^6.0.0", + "next-mdx-remote-client": "^1.1.7", "next-seo": "^6.5.0", "next-themes": "catalog:", "nuqs": "^2.8.1", diff --git a/apps/www/pages/changelog.tsx b/apps/www/pages/changelog.tsx index 80068a161d..7862a3e72b 100644 --- a/apps/www/pages/changelog.tsx +++ b/apps/www/pages/changelog.tsx @@ -2,8 +2,8 @@ import { useBreakpoint } from 'common' import dayjs from 'dayjs' import { GitCommit, ListFilter, Rss, X } from 'lucide-react' import type { GetServerSideProps } from 'next' -import type { MDXRemoteSerializeResult } from 'next-mdx-remote' -import { MDXRemote } from 'next-mdx-remote' +import { MDXClient } from 'next-mdx-remote-client/csr' +import type { SerializeResult as MDXRemoteSerializeResult } from 'next-mdx-remote-client/serialize' import { NextSeo } from 'next-seo' import Head from 'next/head' import Link from 'next/link' @@ -393,7 +393,11 @@ function ChangelogIndex({ featured, restIndex, allIndex }: PageProps) {
- + {'error' in entry.source ? ( +

Error rendering changelog: {entry.source.error.message}

+ ) : ( + + )}
diff --git a/apps/www/pages/changelog/[slug].tsx b/apps/www/pages/changelog/[slug].tsx index 290a927242..2242c36e77 100644 --- a/apps/www/pages/changelog/[slug].tsx +++ b/apps/www/pages/changelog/[slug].tsx @@ -1,6 +1,6 @@ import dayjs from 'dayjs' import type { GetStaticPaths, GetStaticProps } from 'next' -import { MDXRemote, type MDXRemoteSerializeResult } from 'next-mdx-remote' +import { MDXClient, type SerializeResult as MDXRemoteSerializeResult } from 'next-mdx-remote-client' import { NextSeo } from 'next-seo' import Head from 'next/head' import Link from 'next/link' @@ -62,7 +62,11 @@ const ChangelogDetailPage = ({ title, url, created_at, slug, source, labels }: P
- + {'error' in source ? ( +

Error rendering blog post: {source.error.message}

+ ) : ( + + )}
diff --git a/apps/www/pages/customers/[slug].tsx b/apps/www/pages/customers/[slug].tsx index ad203de89d..2627125e97 100644 --- a/apps/www/pages/customers/[slug].tsx +++ b/apps/www/pages/customers/[slug].tsx @@ -8,7 +8,7 @@ import { mdxSerialize } from '~/lib/mdx/mdxSerialize' import { getAllPostSlugs, getPostdata, getSortedPosts } from '~/lib/posts' import matter from 'gray-matter' import { ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react' -import { MDXRemote } from 'next-mdx-remote' +import { MDXClient } from 'next-mdx-remote-client/csr' import { NextSeo } from 'next-seo' import Head from 'next/head' import Image from 'next/image' @@ -228,7 +228,7 @@ function CaseStudyPage(props: any) {
- +
diff --git a/apps/www/pages/events/[slug].tsx b/apps/www/pages/events/[slug].tsx index 5c387c6b09..f3f42e7eaa 100644 --- a/apps/www/pages/events/[slug].tsx +++ b/apps/www/pages/events/[slug].tsx @@ -13,7 +13,7 @@ import utc from 'dayjs/plugin/utc' import matter from 'gray-matter' import { ChevronLeft, X as XIcon } from 'lucide-react' import type { GetStaticProps, InferGetStaticPropsType } from 'next' -import { MDXRemote } from 'next-mdx-remote' +import { MDXClient } from 'next-mdx-remote-client/csr' import { NextSeo } from 'next-seo' import Head from 'next/head' import NextImage from 'next/image' @@ -388,7 +388,7 @@ const EventPage = ({ event }: InferGetStaticPropsType) =>

About this event

- +