1+ import { useSearchParams } from "next/navigation"
12import { useRouter } from "next/router"
23import { useThemeConfig } from "nextra-theme-docs"
34import { Tabs } from "nextra/components"
4- import React , { Children , useEffect , useState } from "react"
5+ import React , { Children , useEffect , MouseEvent } from "react"
56
67interface ChildrenProps {
78 children : React . ReactNode
@@ -33,18 +34,20 @@ const allFrameworks = {
3334 [ ExpressCode . name ] : "Express" ,
3435}
3536
36- const findTabIndex = ( frameworks : Record < string , string > , tab : string ) => {
37- // TODO: Slugify instead of matching on indexes
38- return Object . values ( frameworks ) . findIndex (
39- ( f ) => f . toLowerCase ( ) === tab . toLowerCase ( )
40- )
37+ /**
38+ * Replace all non-alphabetic characters with a hyphen
39+ *
40+ * @param url - URL to parse
41+ * @returns - A string parsed from the URL
42+ */
43+ const parseParams = ( url : string ) : string => {
44+ let parsedUrl = url . toLowerCase ( ) . replaceAll ( / [ ^ a - z A - z ] + / g, "-" )
45+ return parsedUrl . endsWith ( "-" ) ? parsedUrl . slice ( 0 , - 1 ) : parsedUrl
4146}
4247
4348export function Code ( { children } : ChildrenProps ) {
4449 const router = useRouter ( )
45- const {
46- query : { framework } ,
47- } = router
50+ const searchParams = useSearchParams ( )
4851 const childs = Children . toArray ( children )
4952 const { project } = useThemeConfig ( )
5053
@@ -54,29 +57,39 @@ export function Code({ children }: ChildrenProps) {
5457 )
5558
5659 const renderedFrameworks = withNextJsPages ? allFrameworks : baseFrameworks
57- const [ tabIndex , setTabIndex ] = useState ( 0 )
60+
61+ const updateFrameworkStorage = ( value : string ) : void => {
62+ const params = new URLSearchParams ( searchParams ?. toString ( ) )
63+ params . set ( "framework" , value )
64+ router . push ( `${ router . pathname } ?${ params . toString ( ) } ` )
65+ }
66+
67+ const handleClickFramework = ( event : MouseEvent < HTMLDivElement > ) => {
68+ if ( ! ( event . target instanceof HTMLButtonElement ) ) return
69+ const { textContent } = event . target as unknown as HTMLDivElement
70+ updateFrameworkStorage ( parseParams ( textContent ! ) )
71+ }
5872
5973 useEffect ( ( ) => {
60- const savedTabPreference = Number (
61- window . localStorage . getItem ( AUTHJS_TAB_KEY )
62- )
63- if ( framework ) {
64- window . localStorage . setItem (
65- AUTHJS_TAB_KEY ,
66- String ( findTabIndex ( renderedFrameworks , framework as string ) )
67- )
68- setTabIndex ( findTabIndex ( renderedFrameworks , framework as string ) )
69- } else if ( savedTabPreference ) {
70- setTabIndex ( savedTabPreference )
74+ const length = Object . keys ( renderedFrameworks ) . length
75+ const getFrameworkStorage = window . localStorage . getItem ( AUTHJS_TAB_KEY )
76+ const indexFramework = parseInt ( getFrameworkStorage ?? "0" ) % length
77+ if ( ! getFrameworkStorage ) {
78+ window . localStorage . setItem ( AUTHJS_TAB_KEY , "0" )
7179 }
72- } , [ framework , renderedFrameworks ] )
80+ updateFrameworkStorage (
81+ parseParams ( Object . values ( renderedFrameworks ) [ indexFramework ] )
82+ )
83+ } , [ router . pathname , renderedFrameworks ] )
7384
7485 return (
75- < div className = "[&_div[role='tablist']]:!pb-0" >
86+ < div
87+ className = "[&_div[role='tablist']]:!pb-0"
88+ onClick = { handleClickFramework }
89+ >
7690 < Tabs
7791 storageKey = { AUTHJS_TAB_KEY }
7892 items = { Object . values ( renderedFrameworks ) }
79- selectedIndex = { tabIndex }
8093 >
8194 { Object . keys ( renderedFrameworks ) . map ( ( f ) => {
8295 // @ts -expect-error: Hacky dynamic child wrangling
0 commit comments