diff --git a/apps/docs/app/contributing/ContributingToC.tsx b/apps/docs/app/contributing/ContributingToC.tsx new file mode 100644 index 00000000000..e1d8423f89a --- /dev/null +++ b/apps/docs/app/contributing/ContributingToC.tsx @@ -0,0 +1,82 @@ +'use client' + +import { Menu } from 'lucide-react' +import type { HTMLAttributes } from 'react' +import { useEffect, useState } from 'react' + +import { useBreakpoint } from 'common' +import { cn, Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_ } from 'ui' + +interface TocItem extends HTMLAttributes { + label: string + anchor: string +} + +export function ContributingToc({ className }: { className?: string }) { + const mobileToc = useBreakpoint('xl') + const [tocItems, setTocItems] = useState>([]) + + useEffect(() => { + const headings = [ + ...document.querySelectorAll('article.prose > h2,h3'), + ] as Array + const tocItems = headings + .filter((heading) => !!heading.id) + .map((heading) => ({ + label: heading.textContent.substring(0, heading.textContent.length - 1), // Remove ending `#` + anchor: heading.id, + })) + setTocItems(tocItems) + }, []) + + return mobileToc ? ( + + ) : ( + + ) +} + +function MobileToc({ items, className }: { items: Array; className?: string }) { + const [open, setOpen] = useState(false) + + return ( + + + + + {open ? 'Close table of contents' : 'Open table of contents'} + + + + + + + ) +} + +function TocBase({ items, className }: { items: Array; className?: string }) { + return ( + + ) +} diff --git a/apps/docs/app/contributing/content.mdx b/apps/docs/app/contributing/content.mdx new file mode 100644 index 00000000000..cbee66c3616 --- /dev/null +++ b/apps/docs/app/contributing/content.mdx @@ -0,0 +1,399 @@ +# Contributing to Supabase Docs + +Thanks for contributing to Supabase Docs! Here are a few resources to help you get started. + +The code and content for our docs site are located in the main [Supabase GitHub repo](https://github.com/supabase/supabase), under the `apps/docs` directory. + +In the repo, you'll also find: + +- The [developers guide](https://github.com/supabase/supabase/blob/master/apps/docs/DEVELOPERS.md), which will help you set up your local machine to develop the docs site +- The [contributing guide](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md), which goes over the content organization and some general guidelines for writing docs content + +## Components + +Our docs content is mainly written in MDX. Aside from standard GitHub-flavored Markdown, you can use the following helper components to help you organize and display your content: + +### Accordion + +For content that requires progressive disclosure: + +```mdx + +
+ + + Your content here. + + + +
+
+ + + More content here. + + + +
+
+``` + + +
+ + + Your content here. + + + +
+
+ + + More content here. + + + +
+
+ +### Admonition + +For extra information that doesn't fit into the main flow. There are 5 supported types of admonitions: + +- `danger` to warn the user about any missteps that could cause data loss or data leaks +- `deprecation` to notify the user about features that are (or will soon be) deprecated +- `caution` to warn about anything that could cause a bug or serious user inconvenience +- `tip` to point out helpful but optional actions +- `note` for anything else + +Leave a blank line between the admonition tag and the contained content. This will prevent Prettier from trying to break the lines within the content. + +```mdx + + +This could lead to data loss! + + + + + +This feature is deprecated. + + + + + +You should make sure you don't set this up wrong. + + + + + +In certain cases, you may want to do this. + + + + + +Additional helpful information. + + +``` + + + +This could lead to data loss! + + + + + +This feature is deprecated. + + + + + +You should make sure you don't set this up wrong. + + + + + +In certain cases, you may want to do this. + + + + + +Additional helpful information. + + + +### Icons + +The following icons are available. They can be styled with [Tailwind](https://tailwindcss.com/) classes: + +```mdx + + + +``` + +
+ + + +
+ +### Image + +You can include images with regular Markdown syntax: + +```mdx +![Supabase architectural diagram](/docs/img/supabase-architecture.svg) +``` + +![Supabase architectural diagram](/docs/img/supabase-architecture.svg) + +If your image has alternate light and dark versions, or you want to make it zoomable, you can also use the image component: + +```mdx +Supabase architectural diagram +``` + +Supabase architectural diagram + +### Project Variables + +Some guides and tutorials will require that users copy their Supabase project URL and anon key. You can provide those inline if the user is signed in: + +```mdx + + +``` + + + + +### Step Hike + +For tutorials, which feature step-by-step instructions, often with accompanying code, we use the `StepHike` pattern: + +````mdx + + + + + + + Explanation of what to do first. + + + + + + ```sql + select ... + ``` + + + + + + + + + + Explanation of what to do next. This stretches the full width of the section: Sweet tiramisu apple biscuit candy cake. Orange ipsum muffin cookie cake biscuit. Orange muffin vanilla sweet sugar candy. Sprinkles jelly sweet orange candy cream. + + + + + + +```` + + + + + + + + Explanation of what to do first. + + + + + + ```sql + select ... + ``` + + + + + + + + + + Explanation of what to do next. This stretches the full width of the section: Sweet tiramisu apple biscuit candy cake. Orange ipsum muffin cookie cake biscuit. Orange muffin vanilla sweet sugar candy. Sprinkles jelly sweet orange candy cream. + + + + + + + + +### Tabs + +Use tabs when users can select between multiple versions of the content. For example, the content might differ based on language or package manager. + +If you include the `queryGroup` prop, the user's selection will sync with other tab groups. Leave out this prop to omit this behavior. + +````mdx + + + +```js +const supabase = createSupabaseClient() +``` + + + + +```dart +void main() async { + Supabase.initialize(); +} +``` + + + +```` + + + + +```js +const supabase = createSupabaseClient() +``` + + + + +```dart +void main() async { + Supabase.initialize(); +} +``` + + + + +## Partials + +We incorporate content reuse in the docs to avoid duplication. If you find yourself writing the same content over and over, you can put it in a partial instead. Here are some examples of commonly used partials: + + +
+ + + ```mdx + + ``` + + + + + +
+
+ + + ```mdx + + ``` + + + + + +
+
+ +To make a new partial: + +1. Make a new MDX file in `apps/docs/components/MDX`. +1. Write your reusable content. +1. Inside `apps/docs/components/MDX/partials.tsx`, import and re-export your partial. +1. Inside `apps/docs/features/docs/mdx.shared.tsx`, import your partial and include it in the `components` object. +1. You can now use your partial inside any other MDX file by using: ``. diff --git a/apps/docs/app/contributing/page.tsx b/apps/docs/app/contributing/page.tsx new file mode 100644 index 00000000000..666836b4d07 --- /dev/null +++ b/apps/docs/app/contributing/page.tsx @@ -0,0 +1,26 @@ +import { readFile } from 'node:fs/promises' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +import { ContributingToc } from '~/app/contributing/ContributingToC' +import { MDXProviderGuides } from '~/features/docs/GuidesMdx.client' +import { MDXRemoteBase } from '~/features/docs/MdxBase' +import { SidebarSkeleton } from '~/layouts/MainSkeleton' + +export default async function ContributingPage() { + const contentFile = join(dirname(fileURLToPath(import.meta.url)), 'content.mdx') + const content = await readFile(contentFile, 'utf-8') + + return ( + +
+
+ + + +
+ +
+
+ ) +} diff --git a/apps/docs/app/error.tsx b/apps/docs/app/error.tsx index ab0dd867544..3c721fbeb9d 100644 --- a/apps/docs/app/error.tsx +++ b/apps/docs/app/error.tsx @@ -4,13 +4,18 @@ import Link from 'next/link' import { Button } from 'ui' const ErrorPage = () => ( -
+
Sorry, something went wrong - +
+ + +
) diff --git a/apps/docs/app/guides/database/database-advisors/page.tsx b/apps/docs/app/guides/database/database-advisors/page.tsx index dd4b0816acc..184c8fee410 100644 --- a/apps/docs/app/guides/database/database-advisors/page.tsx +++ b/apps/docs/app/guides/database/database-advisors/page.tsx @@ -6,7 +6,8 @@ import rehypeSlug from 'rehype-slug' import { Heading } from 'ui' import { genGuideMeta } from '~/features/docs/GuidesMdx.utils' -import { GuideTemplate, MDXRemoteGuides, newEditLink } from '~/features/docs/GuidesMdx.template' +import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import { fetchRevalidatePerDay } from '~/features/helpers.fetch' import { Tabs, TabPanel } from '~/features/ui/Tabs' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' @@ -54,7 +55,7 @@ const DatabaseAdvisorDocs = async () => { return ( - + Available checks {lints.map((lint) => ( @@ -64,7 +65,7 @@ const DatabaseAdvisorDocs = async () => { label={capitalize(getBasename(lint.path).replace(/_/g, ' '))} >
- +
))} diff --git a/apps/docs/app/guides/layout.tsx b/apps/docs/app/guides/layout.tsx index 1c479c6a6d7..8df012ac97c 100644 --- a/apps/docs/app/guides/layout.tsx +++ b/apps/docs/app/guides/layout.tsx @@ -2,7 +2,8 @@ import { usePathname } from 'next/navigation' import { type PropsWithChildren } from 'react' -import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' + +import { getMenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu.utils' import Layout from '~/layouts/guides' const GuidesLayout = ({ children }: PropsWithChildren) => { @@ -12,39 +13,4 @@ const GuidesLayout = ({ children }: PropsWithChildren) => { return {children} } -export const getMenuId = (pathname: string | null) => { - pathname = (pathname ??= '').replace(/^\/guides\//, '') - - switch (true) { - case pathname.startsWith('ai'): - return MenuId.Ai - case pathname.startsWith('api'): - return MenuId.Api - case pathname.startsWith('auth'): - return MenuId.Auth - case pathname.startsWith('cli'): - return MenuId.Cli - case pathname.startsWith('database'): - return MenuId.Database - case pathname.startsWith('functions'): - return MenuId.Functions - case pathname.startsWith('getting-started'): - return MenuId.GettingStarted - case pathname.startsWith('graphql'): - return MenuId.Graphql - case pathname.startsWith('platform'): - return MenuId.Platform - case pathname.startsWith('realtime'): - return MenuId.Realtime - case pathname.startsWith('resources'): - return MenuId.Resources - case pathname.startsWith('self-hosting'): - return MenuId.SelfHosting - case pathname.startsWith('storage'): - return MenuId.Storage - default: - return MenuId.GettingStarted - } -} - export default GuidesLayout diff --git a/apps/docs/app/guides/self-hosting/analytics/config/page.tsx b/apps/docs/app/guides/self-hosting/analytics/config/page.tsx index b24428be893..d397c0003f0 100644 --- a/apps/docs/app/guides/self-hosting/analytics/config/page.tsx +++ b/apps/docs/app/guides/self-hosting/analytics/config/page.tsx @@ -1,6 +1,7 @@ import Param from '~/components/Params' import { genGuideMeta } from '~/features/docs/GuidesMdx.utils' -import { GuideTemplate, MDXRemoteGuides, newEditLink } from '~/features/docs/GuidesMdx.template' +import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import specAnalyticsV0 from '~/spec/analytics_v0_config.yaml' assert { type: 'yml' } const meta = { @@ -23,7 +24,7 @@ const AnalyticsConfigPage = async () => { 'supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/analytics/config.tsx' )} > - +
{specAnalyticsV0.info.tags.map( diff --git a/apps/docs/app/guides/self-hosting/auth/config/page.tsx b/apps/docs/app/guides/self-hosting/auth/config/page.tsx index 8e08f64b976..d8a33d04694 100644 --- a/apps/docs/app/guides/self-hosting/auth/config/page.tsx +++ b/apps/docs/app/guides/self-hosting/auth/config/page.tsx @@ -1,6 +1,7 @@ import Param from '~/components/Params' import { genGuideMeta } from '~/features/docs/GuidesMdx.utils' -import { GuideTemplate, MDXRemoteGuides, newEditLink } from '~/features/docs/GuidesMdx.template' +import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import specAuthV1 from '~/spec/gotrue_v1_config.yaml' assert { type: 'yml' } const meta = { @@ -23,7 +24,7 @@ const AuthConfigPage = async () => { 'supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/auth/config.tsx' )} > - +
{specAuthV1.info.tags.map((tag: ReturnType['info']['tags']) => { diff --git a/apps/docs/app/guides/self-hosting/realtime/config/page.tsx b/apps/docs/app/guides/self-hosting/realtime/config/page.tsx index 4d56aad32f9..01180ba859c 100644 --- a/apps/docs/app/guides/self-hosting/realtime/config/page.tsx +++ b/apps/docs/app/guides/self-hosting/realtime/config/page.tsx @@ -1,6 +1,7 @@ import Param from '~/components/Params' import { genGuideMeta } from '~/features/docs/GuidesMdx.utils' -import { GuideTemplate, MDXRemoteGuides, newEditLink } from '~/features/docs/GuidesMdx.template' +import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import specRealtimeV0 from '~/spec/realtime_v0_config.yaml' assert { type: 'yml' } const meta = { @@ -23,7 +24,7 @@ const RealtimeConfigPage = async () => { 'supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/realtime/config.tsx' )} > - +
{specRealtimeV0.info.tags.map((tag: ReturnType['info']['tags']) => { diff --git a/apps/docs/app/guides/self-hosting/storage/config/page.tsx b/apps/docs/app/guides/self-hosting/storage/config/page.tsx index 2af560e505a..766bc4d190a 100644 --- a/apps/docs/app/guides/self-hosting/storage/config/page.tsx +++ b/apps/docs/app/guides/self-hosting/storage/config/page.tsx @@ -1,6 +1,7 @@ import Param from '~/components/Params' import { genGuideMeta } from '~/features/docs/GuidesMdx.utils' -import { GuideTemplate, MDXRemoteGuides, newEditLink } from '~/features/docs/GuidesMdx.template' +import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import specStorageV0 from '~/spec/storage_v0_config.yaml' assert { type: 'yml' } const meta = { @@ -23,7 +24,7 @@ const StorageConfigPage = async () => { 'supabase/supabase/blob/master/apps/docs/pages/guides/self-hosting/storage/config.tsx' )} > - +
{specStorageV0.info.tags.map((tag: ReturnType['info']['tags']) => { diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index 37c3b7203db..a35a75df6e3 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -9,6 +9,7 @@ import { type Metadata, type Viewport } from 'next' import { BASE_PATH } from '~/lib/constants' import { GlobalProviders } from '~/features/app.providers' +import { TopNavSkeleton } from '~/layouts/MainSkeleton' const metadata: Metadata = { applicationName: 'Supabase Docs', @@ -45,7 +46,9 @@ const RootLayout = ({ children }: { children: React.ReactNode }) => { return ( - {children} + + {children} + ) diff --git a/apps/docs/app/not-found/layout.tsx b/apps/docs/app/not-found/layout.tsx index 516ffce7a1f..b34cd4356b2 100644 --- a/apps/docs/app/not-found/layout.tsx +++ b/apps/docs/app/not-found/layout.tsx @@ -1,7 +1,7 @@ import { type Metadata } from 'next' import { type PropsWithChildren } from 'react' import { LayoutMainContent } from '~/layouts/DefaultLayout' -import { MainSkeleton } from '~/layouts/MainSkeleton' +import { SidebarSkeleton } from '~/layouts/MainSkeleton' const metadata: Metadata = { title: 'Not found', @@ -11,9 +11,9 @@ const metadata: Metadata = { } const NotFoundLayout = ({ children }: PropsWithChildren) => ( - + {children} - + ) export default NotFoundLayout diff --git a/apps/docs/components/Breadcrumbs.tsx b/apps/docs/components/Breadcrumbs.tsx index f596cac7e49..c8225015f67 100644 --- a/apps/docs/components/Breadcrumbs.tsx +++ b/apps/docs/components/Breadcrumbs.tsx @@ -23,7 +23,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from 'ui' -import { getMenuId } from '../app/guides/layout' +import { getMenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu.utils' import { useBreakpoint } from 'common' import * as NavItems from './Navigation/NavigationMenu/NavigationMenu.constants' diff --git a/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx b/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx index 8e539d8b63b..18fef33a67b 100644 --- a/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx @@ -28,7 +28,6 @@ import { IconMenuDevCli, IconGitHub, IconSupport, - IconTerraform, IconTroubleshooting, IconBranching, } from './MenuIcons' @@ -89,6 +88,8 @@ function getMenuIcon(menuKey: string, width: number = 16, height: number = 16, c return case 'support': return + case 'contributing': + return default: return } diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 10cfa90ebc7..ee479ac4e75 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -1,3 +1,4 @@ +import { IS_DEV } from '~/lib/constants' import type { GlobalMenuItems, NavMenuConstant, References } from '../Navigation.types' export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [ @@ -191,6 +192,11 @@ export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [ icon: 'status', href: 'https://status.supabase.com/', }, + { + label: 'Contributing', + icon: 'contributing', + href: '/contributing' as `/${string}`, + }, ], ], }, diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts index e39582af7f7..28633a25ab9 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react' import { usePathname } from 'next/navigation' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import type { ICommonItem } from '~/components/reference/Reference.types' import type { Json } from '~/types' import { menuState } from '../../../hooks/useMenuState' @@ -105,3 +106,38 @@ export const useCloseMenuOnRouteChange = () => { menuState.setMenuMobileOpen(false) }, [pathname]) } + +export const getMenuId = (pathname: string | null) => { + pathname = (pathname ??= '').replace(/^\/guides\//, '') + + switch (true) { + case pathname.startsWith('ai'): + return MenuId.Ai + case pathname.startsWith('api'): + return MenuId.Api + case pathname.startsWith('auth'): + return MenuId.Auth + case pathname.startsWith('cli'): + return MenuId.Cli + case pathname.startsWith('database'): + return MenuId.Database + case pathname.startsWith('functions'): + return MenuId.Functions + case pathname.startsWith('getting-started'): + return MenuId.GettingStarted + case pathname.startsWith('graphql'): + return MenuId.Graphql + case pathname.startsWith('platform'): + return MenuId.Platform + case pathname.startsWith('realtime'): + return MenuId.Realtime + case pathname.startsWith('resources'): + return MenuId.Resources + case pathname.startsWith('self-hosting'): + return MenuId.SelfHosting + case pathname.startsWith('storage'): + return MenuId.Storage + default: + return MenuId.GettingStarted + } +} diff --git a/apps/docs/components/Navigation/NavigationMenu/TopNavDropdown.tsx b/apps/docs/components/Navigation/NavigationMenu/TopNavDropdown.tsx index dc33416049b..5b102255a38 100644 --- a/apps/docs/components/Navigation/NavigationMenu/TopNavDropdown.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/TopNavDropdown.tsx @@ -1,6 +1,6 @@ 'use client' -import React from 'react' +import React, { Fragment } from 'react' import Link from 'next/link' import { useTheme } from 'next-themes' import { Menu } from 'lucide-react' @@ -72,7 +72,7 @@ const TopNavDropdown = () => { {menu.map((menuSection, sectionIdx) => ( - <> + {sectionIdx !== 0 && } {menuSection.map((sectionItem, itemIdx) => ( { ))} - + ))} diff --git a/apps/docs/components/reference/RefSectionHandler.tsx b/apps/docs/components/reference/RefSectionHandler.tsx index 22174b29be3..91e73b90dc4 100644 --- a/apps/docs/components/reference/RefSectionHandler.tsx +++ b/apps/docs/components/reference/RefSectionHandler.tsx @@ -11,7 +11,7 @@ import ApiOperationSection from './ApiOperationSection' import CliCommandSection from './CLICommandSection' import OldVersionAlert from './OldVersionAlert' import type { IAPISpec, ICommonSection, IRefStaticDoc, ISpec, TypeSpec } from './Reference.types' -import { MainSkeleton } from '~/layouts/MainSkeleton' +import { SidebarSkeleton, TopNavSkeleton } from '~/layouts/MainSkeleton' import MgmtApiOperationSection from '~/components/reference/MgmtApiOperationSection' interface RefSectionHandlerProps { @@ -80,66 +80,68 @@ const RefSectionHandler = (props: RefSectionHandlerProps) => { - - {props.isOldVersion && } - - {props.sections.map((section, i) => { - const sectionType = section.type - switch (sectionType) { - case 'markdown': - const markdownData = props.pageProps.docs.find((doc) => doc.id === section.id) + + + {props.isOldVersion && } + + {props.sections.map((section, i) => { + const sectionType = section.type + switch (sectionType) { + case 'markdown': + const markdownData = props.pageProps.docs.find((doc) => doc.id === section.id) - return ( - - ) - case 'function': - return ( - - ) - case 'cli-command': - return ( - - ) - case 'operation': - if (props.type === 'mgmt-api') { return ( - + ) + case 'function': + return ( + ) - } else { + case 'cli-command': return ( - ) - } - default: - throw new Error(`Unknown common section type '${sectionType}'`) - } - })} - - + case 'operation': + if (props.type === 'mgmt-api') { + return ( + + ) + } else { + return ( + + ) + } + default: + throw new Error(`Unknown common section type '${sectionType}'`) + } + })} + + + ) } diff --git a/apps/docs/features/docs/GuidesMdx.client.tsx b/apps/docs/features/docs/GuidesMdx.client.tsx index a6d81f4a231..b0bc609650b 100644 --- a/apps/docs/features/docs/GuidesMdx.client.tsx +++ b/apps/docs/features/docs/GuidesMdx.client.tsx @@ -7,7 +7,7 @@ import { MDXProvider } from '@mdx-js/react' import { type PropsWithChildren } from 'react' -import { components } from '~/features/docs/mdx.shared' +import { components } from '~/features/docs/MdxBase.shared' const MDXProviderGuides = ({ children }: PropsWithChildren) => ( {children} diff --git a/apps/docs/features/docs/GuidesMdx.template.tsx b/apps/docs/features/docs/GuidesMdx.template.tsx index 46a63b23424..7e5bf96871e 100644 --- a/apps/docs/features/docs/GuidesMdx.template.tsx +++ b/apps/docs/features/docs/GuidesMdx.template.tsx @@ -1,64 +1,15 @@ -import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } -import { remarkCodeHike, type CodeHikeConfig } from '@code-hike/mdx' import { ExternalLink } from 'lucide-react' import { type SerializeOptions } from 'next-mdx-remote/dist/types' -import { MDXRemote } from 'next-mdx-remote/rsc' -import { type ComponentProps, type ReactNode } from 'react' -import remarkGfm from 'remark-gfm' -import rehypeKatex from 'rehype-katex' -import remarkMath from 'remark-math' +import { type ReactNode } from 'react' + import { cn } from 'ui' + +import Breadcrumbs from '~/components/Breadcrumbs' import GuidesTableOfContents from '~/components/GuidesTableOfContents' -import { components } from '~/features/docs/mdx.shared' +import { MDXProviderGuides } from '~/features/docs/GuidesMdx.client' +import { MDXRemoteBase } from '~/features/docs/MdxBase' import type { WithRequired } from '~/features/helpers.types' import { type GuideFrontmatter } from '~/lib/docs' -import { MDXProviderGuides } from './GuidesMdx.client' -import Breadcrumbs from '~/components/Breadcrumbs' - -const codeHikeOptions: CodeHikeConfig = { - theme: codeHikeTheme, - lineNumbers: true, - showCopyButton: true, - skipLanguages: [], - autoImport: false, -} - -const mdxOptions: SerializeOptions = { - mdxOptions: { - useDynamicImport: true, - remarkPlugins: [ - [remarkMath, { singleDollarTextMath: false }], - remarkGfm, - [remarkCodeHike, codeHikeOptions], - ], - rehypePlugins: [rehypeKatex as any], - }, -} - -const MDXRemoteGuides = ({ options = {}, ...props }: ComponentProps) => { - const { mdxOptions: { remarkPlugins, rehypePlugins, ...otherMdxOptions } = {}, ...otherOptions } = - options - const { - mdxOptions: { - remarkPlugins: originalRemarkPlugins, - rehypePlugins: originalRehypePlugins, - ...originalMdxOptions - } = {}, - } = mdxOptions - - const finalOptions = { - ...mdxOptions, - ...otherOptions, - mdxOptions: { - ...originalMdxOptions, - ...otherMdxOptions, - remarkPlugins: [...(originalRemarkPlugins ?? []), ...(remarkPlugins ?? [])], - rehypePlugins: [...(originalRehypePlugins ?? []), ...(rehypePlugins ?? [])], - }, - } as SerializeOptions - - return -} const EDIT_LINK_SYMBOL = Symbol('edit link') interface EditLink { @@ -133,7 +84,7 @@ const GuideTemplate = ({ meta, content, children, editLink, mdxOptions }: GuideT )}
- {content && } + {content && } {children}
@@ -177,4 +128,4 @@ const GuideTemplate = ({ meta, content, children, editLink, mdxOptions }: GuideT ) } -export { GuideTemplate, MDXRemoteGuides, newEditLink } +export { GuideTemplate, newEditLink } diff --git a/apps/docs/features/docs/mdx.shared.tsx b/apps/docs/features/docs/MdxBase.shared.tsx similarity index 100% rename from apps/docs/features/docs/mdx.shared.tsx rename to apps/docs/features/docs/MdxBase.shared.tsx diff --git a/apps/docs/features/docs/MdxBase.tsx b/apps/docs/features/docs/MdxBase.tsx new file mode 100644 index 00000000000..9cb1e104ced --- /dev/null +++ b/apps/docs/features/docs/MdxBase.tsx @@ -0,0 +1,57 @@ +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } +import { remarkCodeHike, type CodeHikeConfig } from '@code-hike/mdx' +import { type SerializeOptions } from 'next-mdx-remote/dist/types' +import { MDXRemote } from 'next-mdx-remote/rsc' +import { type ComponentProps } from 'react' +import remarkGfm from 'remark-gfm' +import rehypeKatex from 'rehype-katex' +import remarkMath from 'remark-math' + +import { components } from '~/features/docs/MdxBase.shared' + +const codeHikeOptions: CodeHikeConfig = { + theme: codeHikeTheme, + lineNumbers: true, + showCopyButton: true, + skipLanguages: [], + autoImport: false, +} + +const mdxOptions: SerializeOptions = { + mdxOptions: { + useDynamicImport: true, + remarkPlugins: [ + [remarkMath, { singleDollarTextMath: false }], + remarkGfm, + [remarkCodeHike, codeHikeOptions], + ], + rehypePlugins: [rehypeKatex as any], + }, +} + +const MDXRemoteBase = ({ options = {}, ...props }: ComponentProps) => { + const { mdxOptions: { remarkPlugins, rehypePlugins, ...otherMdxOptions } = {}, ...otherOptions } = + options + const { + mdxOptions: { + remarkPlugins: originalRemarkPlugins, + rehypePlugins: originalRehypePlugins, + ...originalMdxOptions + } = {}, + } = mdxOptions + + const finalOptions = { + ...mdxOptions, + ...otherOptions, + mdxOptions: { + ...originalMdxOptions, + ...otherMdxOptions, + remarkPlugins: [...(originalRemarkPlugins ?? []), ...(remarkPlugins ?? [])], + rehypePlugins: [...(originalRehypePlugins ?? []), ...(rehypePlugins ?? [])], + }, + } as SerializeOptions + + return +} + +export { MDXRemoteBase } diff --git a/apps/docs/layouts/HomeLayout.tsx b/apps/docs/layouts/HomeLayout.tsx index c42cc25945b..4c04c9fc9cd 100644 --- a/apps/docs/layouts/HomeLayout.tsx +++ b/apps/docs/layouts/HomeLayout.tsx @@ -2,11 +2,11 @@ import { type PropsWithChildren } from 'react' import HomePageCover from '~/components/HomePageCover' import { LayoutMainContent } from './DefaultLayout' -import { MainSkeleton } from './MainSkeleton' +import { SidebarSkeleton } from './MainSkeleton' const HomeLayout = ({ children }: PropsWithChildren) => { return ( - +
@@ -15,7 +15,7 @@ const HomeLayout = ({ children }: PropsWithChildren) => {
- + ) } diff --git a/apps/docs/layouts/MainSkeleton.tsx b/apps/docs/layouts/MainSkeleton.tsx index 798c3644ef0..a0c9176f42d 100644 --- a/apps/docs/layouts/MainSkeleton.tsx +++ b/apps/docs/layouts/MainSkeleton.tsx @@ -1,14 +1,17 @@ 'use client' -import { type PropsWithChildren, memo, useEffect, useRef } from 'react' import dynamic from 'next/dynamic' +import { memo, useEffect, type PropsWithChildren, type ReactNode } from 'react' + import { cn } from 'ui' + +import DefaultNavigationMenu, { + MenuId, +} from '~/components/Navigation/NavigationMenu/NavigationMenu' +import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar' import { DOCS_CONTENT_CONTAINER_ID } from '~/features/ui/helpers.constants' import { menuState, useMenuMobileOpen } from '~/hooks/useMenuState' -import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' -import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar' - const Footer = dynamic(() => import('~/components/Navigation/Footer')) const NavigationMenu = dynamic( () => import('~/components/Navigation/NavigationMenu/NavigationMenu') @@ -264,7 +267,7 @@ const Container = memo(function Container({ ) }) -const NavContainer = memo(function NavContainer({ menuId }: { menuId: MenuId }) { +const NavContainer = memo(function NavContainer({ children }: PropsWithChildren) { const mobileMenuOpen = useMenuMobileOpen() return ( @@ -313,53 +316,65 @@ const NavContainer = memo(function NavContainer({ menuId }: { menuId: MenuId }) 'lg:opacity-100 lg:visible' )} > - + {children}
) }) -function MainSkeleton({ children, menuId }: PropsWithChildren<{ menuId?: MenuId }>) { - const ref = useRef(null) - const mobileMenuOpen = useMenuMobileOpen() - const hideSideNav = !menuId +interface SkeletonProps extends PropsWithChildren { + menuId?: MenuId + NavigationMenu?: ReactNode +} +function TopNavSkeleton({ children }) { return (
-
+
-
- {!hideSideNav && } - -
- -
-
- {!hideSideNav && } -
-
- {children} -
-
- -
-
+ {children}
) } -export { MainSkeleton } +function SidebarSkeleton({ children, menuId, NavigationMenu }: SkeletonProps) { + const mobileMenuOpen = useMenuMobileOpen() + const hideSideNav = !menuId + + return ( +
+ {!hideSideNav && ( + {NavigationMenu ?? } + )} + +
+ +
+
+ {!hideSideNav && } +
+
+ {children} +
+
+ +
+
+ ) +} + +export { TopNavSkeleton, SidebarSkeleton } diff --git a/apps/docs/layouts/guides/index.tsx b/apps/docs/layouts/guides/index.tsx index dd785a54b31..c625530ddcf 100644 --- a/apps/docs/layouts/guides/index.tsx +++ b/apps/docs/layouts/guides/index.tsx @@ -7,7 +7,7 @@ import { type FC } from 'react' import { FooterHelpCalloutType } from '~/components/FooterHelpCallout' import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import { LayoutMainContent } from '~/layouts/DefaultLayout' -import { MainSkeleton } from '~/layouts/MainSkeleton' +import { SidebarSkeleton } from '~/layouts/MainSkeleton' interface Props { meta?: { @@ -33,11 +33,9 @@ const Layout: FC = (props) => { const menuId = props.menuId return ( - <> - - {props.children} - - + + {props.children} + ) }