Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add slugify to select tab framework #11951

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions docs/components/Code/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useSearchParams } from "next/navigation"
import { useRouter } from "next/router"
import { useThemeConfig } from "nextra-theme-docs"
import { Tabs } from "nextra/components"
import React, { Children, useEffect, useState } from "react"
import React, { Children, useEffect, MouseEvent } from "react"

interface ChildrenProps {
children: React.ReactNode
Expand Down Expand Up @@ -33,18 +34,20 @@
[ExpressCode.name]: "Express",
}

const findTabIndex = (frameworks: Record<string, string>, tab: string) => {
// TODO: Slugify instead of matching on indexes
return Object.values(frameworks).findIndex(
(f) => f.toLowerCase() === tab.toLowerCase()
)
/**
* Replace all non-alphabetic characters with a hyphen
*
* @param url - URL to parse
* @returns - A string parsed from the URL
*/
const parseParams = (url: string): string => {
let parsedUrl = url.toLowerCase().replaceAll(/[^a-zA-z]+/g, "-")

Check warning

Code scanning / CodeQL

Overly permissive regular expression range Medium documentation

Suspicious character range that overlaps with a-z in the same character class, and is equivalent to [A-Z\[\]^_`a-z].
return parsedUrl.endsWith("-") ? parsedUrl.slice(0, -1) : parsedUrl
}

export function Code({ children }: ChildrenProps) {
const router = useRouter()
const {
query: { framework },
} = router
const searchParams = useSearchParams()
const childs = Children.toArray(children)
const { project } = useThemeConfig()

Expand All @@ -54,29 +57,39 @@
)

const renderedFrameworks = withNextJsPages ? allFrameworks : baseFrameworks
const [tabIndex, setTabIndex] = useState(0)

const updateFrameworkStorage = (value: string): void => {
const params = new URLSearchParams(searchParams?.toString())
params.set("framework", value)
router.push(`${router.pathname}?${params.toString()}`)
}

const handleClickFramework = (event: MouseEvent<HTMLDivElement>) => {
if (!(event.target instanceof HTMLButtonElement)) return
const { textContent } = event.target as unknown as HTMLDivElement
updateFrameworkStorage(parseParams(textContent!))
}

useEffect(() => {
const savedTabPreference = Number(
window.localStorage.getItem(AUTHJS_TAB_KEY)
)
if (framework) {
window.localStorage.setItem(
AUTHJS_TAB_KEY,
String(findTabIndex(renderedFrameworks, framework as string))
)
setTabIndex(findTabIndex(renderedFrameworks, framework as string))
} else if (savedTabPreference) {
setTabIndex(savedTabPreference)
const length = Object.keys(renderedFrameworks).length
const getFrameworkStorage = window.localStorage.getItem(AUTHJS_TAB_KEY)
const indexFramework = parseInt(getFrameworkStorage ?? "0") % length
if (!getFrameworkStorage) {
window.localStorage.setItem(AUTHJS_TAB_KEY, "0")
}
}, [framework, renderedFrameworks])
updateFrameworkStorage(
parseParams(Object.values(renderedFrameworks)[indexFramework])
)
}, [router.pathname, renderedFrameworks])

return (
<div className="[&_div[role='tablist']]:!pb-0">
<div
className="[&_div[role='tablist']]:!pb-0"
onClick={handleClickFramework}
>
<Tabs
storageKey={AUTHJS_TAB_KEY}
items={Object.values(renderedFrameworks)}
selectedIndex={tabIndex}
>
{Object.keys(renderedFrameworks).map((f) => {
// @ts-expect-error: Hacky dynamic child wrangling
Expand Down
Loading