diff --git a/apps/docs/components/Navigation/Navigation.types.ts b/apps/docs/components/Navigation/Navigation.types.ts index 76afaa7b1c6..a644cc7c70d 100644 --- a/apps/docs/components/Navigation/Navigation.types.ts +++ b/apps/docs/components/Navigation/Navigation.types.ts @@ -22,3 +22,14 @@ export interface References { currentVersion?: string } } + +type MenuItem = { + label: string + icon?: string + href?: string + level?: string + hasLightIcon?: boolean + community?: boolean +} + +export type HomepageMenuItems = MenuItem[][] diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx index ad3d9985bb2..6c18375038b 100644 --- a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx @@ -4,153 +4,11 @@ import Link from 'next/link' import { useRouter } from 'next/router' import { Fragment } from 'react' import { Badge } from '~/../../packages/ui' - -const home = [ - [ - { - label: 'Home', - icon: '/img/icons/menu/home', - href: '/', - level: 'home', - }, - { - label: 'Getting Started', - icon: '/img/icons/menu/getting-started', - href: '/guides/getting-started', - level: 'gettingstarted', - }, - ], - [ - { - label: 'Database', - icon: '/img/icons/menu/database', - href: '/guides/database', - level: 'database', - }, - { - label: 'Serverless APIs', - icon: '/img/icons/menu/reference', - href: '/guides/api', - level: 'api', - }, - { - label: 'Auth', - icon: '/img/icons/menu/auth', - href: '/guides/auth', - level: 'auth', - }, - { - label: 'Edge Functions', - icon: '/img/icons/menu/functions', - href: '/guides/functions', - level: 'functions', - }, - { - label: 'Realtime', - icon: '/img/icons/menu/realtime', - href: '/guides/realtime', - level: 'realtime', - }, - { - label: 'Storage', - icon: '/img/icons/menu/storage', - href: '/guides/storage', - level: 'storage', - }, - ], - [ - { - label: 'Platform', - icon: '/img/icons/menu/platform', - href: '/guides/platform', - level: 'platform', - }, - { - label: 'Resources', - icon: '/img/icons/menu/platform', - href: '/guides/resources', - level: 'resources', - }, - { - label: 'Self-Hosting', - icon: '/img/icons/menu/platform', - href: '/guides/self-hosting', - level: 'self_hosting', - }, - { - label: 'Integrations', - icon: '/img/icons/menu/integrations', - hasLightIcon: true, - href: '/guides/integrations', - level: 'integrations', - }, - ], - [ - { - label: 'Client Library Reference', - }, - { - label: 'JavaScript', - icon: '/img/icons/menu/reference-javascript', - href: '/reference/javascript/introduction', - level: 'reference_javascript', - }, - { - label: 'Flutter', - icon: '/img/icons/menu/reference-dart', - href: '/reference/dart/introduction', - level: 'reference_dart', - }, - { - label: 'Python', - icon: '/img/icons/menu/reference-python', - href: '/reference/python/introduction', - level: 'reference_python', - community: true, - }, - { - label: 'C#', - icon: '/img/icons/menu/reference-csharp', - href: '/reference/csharp/introduction', - level: 'reference_csharp', - community: true, - }, - { - label: 'Swift', - icon: '/img/icons/menu/reference-swift', - href: '/reference/swift/introduction', - level: 'reference_swift', - community: true, - }, - { - label: 'Kotlin', - icon: '/img/icons/menu/reference-kotlin', - href: '/reference/kotlin/introduction', - level: 'reference_kotlin', - community: true, - }, - { - label: 'Tools', - }, - { - label: 'Management API', - icon: '/img/icons/menu/reference-api', - href: '/reference/api/introduction', - level: 'reference_javascript', - }, - { - label: 'Supabase CLI', - icon: '/img/icons/menu/reference-cli', - href: '/guides/cli', - level: 'reference_javascript', - }, - ], -] +import { cn } from 'ui/src/utils/cn' +import { HOMEPAGE_MENU_ITEMS } from './NavigationMenu.constants' +import HomeMenuIconPicker from './HomeMenuIconPicker' const NavigationMenuHome = ({ active }) => { - const router = useRouter() - const { isDarkMode } = useTheme() - return (
{ active ? 'opacity-100 ml-0 delay-150' : 'opacity-0 -ml-8 invisible absolute', ].join(' ')} > -
)}
-
- {section.map((link) => { +
+ {section.map((link, i) => { if (!link.href) { return ( - {link.label} - +
) } else { return ( @@ -186,19 +47,11 @@ const NavigationMenuHome = ({ active }) => {
  • - {link.label} + {link?.icon && } {link.label} {link.community && Community}
  • diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenuIconPicker.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIconPicker.tsx new file mode 100644 index 00000000000..07ad9d7f9c0 --- /dev/null +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIconPicker.tsx @@ -0,0 +1,84 @@ +import React from 'react' +import { + IconMenuApi, + IconMenuAuth, + IconMenuCli, + IconMenuCsharp, + IconMenuDatabase, + IconMenuEdgeFunctions, + IconMenuFlutter, + IconMenuGettingStarted, + IconMenuHome, + IconMenuIntegrations, + IconMenuJavascript, + IconMenuPlatform, + IconMenuPython, + IconMenuRealtime, + IconMenuResources, + IconMenuSelfHosting, + IconMenuServerlessApis, + IconMenuStorage, + IconMenuSwift, + IconMenuStatus, +} from './HomeMenuIcons' + +function getMenuIcon(menuKey: string, width: number = 16, height: number = 16) { + switch (menuKey) { + case 'home': + return + case 'getting-started': + return + case 'database': + return + case 'serverless-apis': + return + case 'auth': + return + case 'edge-functions': + return + case 'realtime': + return + case 'storage': + return + case 'platform': + return + case 'resources': + return + case 'self-hosting': + return + case 'integrations': + return + case 'reference-javascript': + return + case 'reference-dart': + return + case 'reference-python': + return + case 'reference-csharp': + return + case 'reference-swift': + return + case 'reference-api': + return + case 'reference-cli': + return + case 'status': + return + default: + return + } +} + +type HomeMenuIconPickerProps = { + icon: string + width?: number + height?: number +} + +export default function HomeMenuIconPicker({ + icon, + width = 16, + height = 16, +}: HomeMenuIconPickerProps) { + return getMenuIcon(icon, width, height) +} diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx new file mode 100644 index 00000000000..73a39c75f59 --- /dev/null +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenuIcons.tsx @@ -0,0 +1,402 @@ +type HomeMenuIcon = { + width?: number + height?: number +} +export function IconMenuHome({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuApi({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuAuth({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuCli({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuCsharp({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuDatabase({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuServerlessApis({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuEdgeFunctions({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuExtensions({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuFlutter({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuGettingStarted({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuIntegrations({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuJavascript({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuPlatform({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuPython({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuRealtime({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuResources({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuSelfHosting({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuStorage({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuSwift({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} + +export function IconMenuStatus({ width = 16, height = 16 }: HomeMenuIcon) { + return ( + + + + ) +} diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 0ec03687ccc..520c7ec03d5 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -1,4 +1,146 @@ -import { References } from '../Navigation.types' +import { References, HomepageMenuItems } from '../Navigation.types' + +export const HOMEPAGE_MENU_ITEMS: HomepageMenuItems = [ + [ + { + label: 'Home', + icon: 'home', + href: '/', + level: 'home', + }, + { + label: 'Getting Started', + icon: 'getting-started', + href: '/guides/getting-started', + level: 'gettingstarted', + }, + ], + [ + { + label: 'Database', + icon: 'database', + href: '/guides/database', + level: 'database', + }, + { + label: 'Serverless APIs', + icon: 'serverless-apis', + href: '/guides/api', + level: 'api', + }, + { + label: 'Auth', + icon: 'auth', + href: '/guides/auth', + level: 'auth', + }, + { + label: 'Edge Functions', + icon: 'edge-functions', + href: '/guides/functions', + level: 'functions', + }, + { + label: 'Realtime', + icon: 'realtime', + href: '/guides/realtime', + level: 'realtime', + }, + { + label: 'Storage', + icon: 'storage', + href: '/guides/storage', + level: 'storage', + }, + ], + [ + { + label: 'Platform', + icon: 'platform', + href: '/guides/platform', + level: 'platform', + }, + { + label: 'Resources', + icon: 'resources', + href: '/guides/resources', + level: 'resources', + }, + { + label: 'Self-Hosting', + icon: 'self-hosting', + href: '/guides/self-hosting', + level: 'self_hosting', + }, + { + label: 'Integrations', + icon: 'integrations', + hasLightIcon: true, + href: '/guides/integrations', + level: 'integrations', + }, + ], + [ + { + label: 'Client Library Reference', + }, + { + label: 'JavaScript', + icon: 'reference-javascript', + href: '/reference/javascript/introduction', + level: 'reference_javascript', + }, + { + label: 'Flutter', + icon: 'reference-dart', + href: '/reference/dart/introduction', + level: 'reference_dart', + }, + { + label: 'Python', + icon: 'reference-python', + href: '/reference/python/introduction', + level: 'reference_python', + community: true, + }, + { + label: 'C#', + icon: 'reference-csharp', + href: '/reference/csharp/introduction', + level: 'reference_csharp', + community: true, + }, + { + label: 'Swift', + icon: 'reference-swift', + href: '/reference/swift/introduction', + level: 'reference_swift', + community: true, + }, + { + label: 'Tools reference', + }, + { + label: 'Management API', + icon: 'reference-api', + href: '/reference/api/introduction', + level: 'reference_javascript', + }, + { + label: 'Supabase CLI', + icon: 'reference-cli', + href: '/guides/cli', + level: 'reference_javascript', + }, + ], + [ + { + label: 'Status', + icon: 'status', + href: 'https://status.supabase.com/', + }, + ], +] export const REFERENCES: References = { javascript: { @@ -301,6 +443,7 @@ export const auth = { }, ], }, + { name: 'Password Reset', url: '/guides/auth/auth-password-reset' }, { name: 'Email Templates', url: '/guides/auth/auth-email-templates' }, ], }, @@ -509,7 +652,7 @@ export const database = { } export const api = { - icon: 'reference', + icon: 'serverless-apis', title: 'Serverless APIs', url: '/guides/api', items: [ @@ -547,7 +690,7 @@ export const api = { } export const functions = { - icon: 'functions', + icon: 'edge-functions', title: 'Edge Functions', url: '/guides/functions', items: [ @@ -834,7 +977,7 @@ export const resources = { export const self_hosting = { title: 'Self-Hosting', - icon: 'resources', + icon: 'self-hosting', url: '/guides/self-hosting', items: [ { name: 'Overview', url: '/guides/self-hosting' }, diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx index cae120747b8..9c15657d064 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx @@ -22,7 +22,7 @@ const NavigationMenuCliList = ({ currentLevel, setLevel, id }) => { icon?: string }) => { return ( -
  • +
  • {icon && } diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx index 22a7d049827..17c8c9d91e8 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx @@ -2,23 +2,10 @@ import { useTheme } from 'common/Providers' import Image from 'next/image' import Link from 'next/link' import { useRouter } from 'next/router' -import React from 'react' +import React, { useEffect, useRef } from 'react' import { IconChevronLeft } from '~/../../packages/ui' import * as Accordion from '@radix-ui/react-accordion' - -const HeaderImage = React.memo(function HeaderImage(props: any) { - const router = useRouter() - const { isDarkMode } = useTheme() - - return ( - {props.icon} - ) -}) +import HomeMenuIconPicker from './HomeMenuIconPicker' const HeaderLink = React.memo(function HeaderLink(props: { title: string @@ -43,6 +30,8 @@ const HeaderLink = React.memo(function HeaderLink(props: { const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any) { const router = useRouter() const { isDarkMode } = useTheme() + const activeItem = props.subItem.url === router.pathname + const activeItemRef = useRef(null) const LinkContainer = (props) => { return ( @@ -52,6 +41,15 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any ) } + useEffect(() => { + // scroll to active item + if (activeItem && activeItemRef.current) { + // this is a hack, but seems a common one on Stackoverflow + setTimeout(() => { + activeItemRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) + }, 0) + } + }) return ( <> {props.subItemIndex === 0 && ( @@ -63,15 +61,15 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any )} -
  • +
  • @@ -120,14 +118,14 @@ const ContentLink = React.memo(function ContentLink(props: any) { const router = useRouter() return ( -
  • +
  • {props.icon && ( @@ -168,8 +166,8 @@ const Content = (props) => { -
    - +
    +
    @@ -179,15 +177,17 @@ const Content = (props) => { return (
    {x.items && x.items.length > 0 ? ( -
    +
    {x.items.map((subItem, subItemIndex) => { return ( - + <> + + ) })}
    diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx index b81f6c5a1dd..1c8a5415074 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx @@ -1,7 +1,7 @@ import * as Accordion from '@radix-ui/react-accordion' import Link from 'next/link' import { useRouter } from 'next/router' -import { IconChevronLeft } from 'ui' +import { IconChevronLeft, IconChevronUp } from 'ui' import * as NavItems from './NavigationMenu.constants' import { find } from 'lodash' @@ -15,24 +15,10 @@ import { RefIdOptions, RefKeyOptions } from './NavigationMenu' import React, { Fragment } from 'react' import { generateAllowedClientLibKeys } from '~/lib/refGenerator/helpers' import { isFuncNotInLibraryOrVersion } from './NavigationMenu.utils' - -const HeaderImage = React.memo(function HeaderImage(props: any) { - const router = useRouter() - const { isDarkMode } = useTheme() - - return ( - {props.icon} - ) -}) +import { cn } from 'ui/src/utils/cn' +import HomeMenuIconPicker from './HomeMenuIconPicker' const HeaderLink = React.memo(function HeaderLink(props: any) { - const router = useRouter() - return ( {props.title ?? props.id} @@ -46,6 +32,8 @@ const FunctionLink = React.memo(function FunctionLink({ icon, library, slug, + isParent = false, + isSubItem = false, }: { title: string name?: string @@ -54,6 +42,8 @@ const FunctionLink = React.memo(function FunctionLink({ product?: string library: string slug: string + isParent: boolean + isSubItem: boolean }) { const router = useRouter() const activeAccordianItem = useMenuActiveRefId() @@ -70,16 +60,29 @@ const FunctionLink = React.memo(function FunctionLink({ const active = activeAccordianItem === id return ( -
  • +
  • {icon && {icon}} {title} + {active && !isSubItem && ( + + )} + {isParent && ( + + )}
  • @@ -121,26 +124,37 @@ const RenderLink = React.memo(function RenderLink(props: any) { value={active ? props.id : ''} > - - - {props.items && - props.items - .filter((item) => props.allowedKeys.includes(item.id)) - .map((item) => { - return ( - - ) - })} - + + {props.items && ( + + {props.items && + props.items + .filter((item) => props.allowedKeys.includes(item.id)) + .map((item) => { + return ( + + ) + })} + + )} ) @@ -239,12 +253,12 @@ const Content: React.FC = ({ id, lib, commonSections, sp
    - +
    -