Skip to content

Commit 9db204b

Browse files
committed
Render the LearnNavLinkCard outside
1 parent cde2275 commit 9db204b

File tree

5 files changed

+239
-138
lines changed

5 files changed

+239
-138
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import cn from "clsx"
2+
import NextLink from "next/link"
3+
import { ArrowRightIcon } from "nextra/icons"
4+
import type { Item } from "nextra/normalize-pages"
5+
import type { ReactElement } from "react"
6+
import { useThemeConfig } from "nextra-theme-docs"
7+
import type { DocsThemeConfig } from "nextra-theme-docs"
8+
9+
interface NavLinkProps {
10+
currentIndex: number
11+
flatDocsDirectories: Item[]
12+
}
13+
14+
const classes = {
15+
link: cn(
16+
"nextra-focus _text-gray-600 dark:_text-gray-400",
17+
"hover:_text-gray-800 dark:hover:_text-gray-200",
18+
"contrast-more:_text-gray-700 contrast-more:dark:_text-gray-100",
19+
"_flex _max-w-[50%] _items-center _gap-1 _py-4 _text-base _font-medium _transition-colors [word-break:break-word] md:_text-lg",
20+
),
21+
icon: cn("_inline _h-5 _shrink-0"),
22+
}
23+
24+
export function ArrowNavLinks({
25+
flatDocsDirectories,
26+
currentIndex,
27+
}: NavLinkProps): ReactElement | null {
28+
const themeConfig = useThemeConfig()
29+
const nav = themeConfig.navigation
30+
const navigation: Exclude<DocsThemeConfig["navigation"], boolean> =
31+
typeof nav === "boolean" ? { prev: nav, next: nav } : nav
32+
let prev = navigation.prev && flatDocsDirectories[currentIndex - 1]
33+
let next = navigation.next && flatDocsDirectories[currentIndex + 1]
34+
35+
if (prev && !prev.isUnderCurrentDocsTree) prev = false
36+
if (next && !next.isUnderCurrentDocsTree) next = false
37+
38+
if (!prev && !next) return null
39+
40+
return (
41+
<div
42+
className={cn(
43+
"_mb-8 _flex _items-center _border-t _pt-8 dark:_border-neutral-800",
44+
"contrast-more:_border-neutral-400 dark:contrast-more:_border-neutral-400",
45+
"print:_hidden",
46+
)}
47+
>
48+
{prev && (
49+
<NextLink
50+
href={prev.route}
51+
title={prev.title}
52+
className={cn(classes.link, "ltr:_pr-4 rtl:_pl-4")}
53+
>
54+
<ArrowRightIcon className={cn(classes.icon, "ltr:_rotate-180")} />
55+
{prev.title}
56+
</NextLink>
57+
)}
58+
{next && (
59+
<NextLink
60+
href={next.route}
61+
title={next.title}
62+
className={cn(
63+
classes.link,
64+
"ltr:_ml-auto ltr:_pl-4 ltr:_text-right rtl:_mr-auto rtl:_pr-4 rtl:_text-left",
65+
)}
66+
>
67+
{next.title}
68+
<ArrowRightIcon className={cn(classes.icon, "rtl:_rotate-180")} />
69+
</NextLink>
70+
)}
71+
</div>
72+
)
73+
}

src/components/nav-links/index.tsx

Lines changed: 2 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,2 @@
1-
import NextLink from "next/link"
2-
import type { Item } from "nextra/normalize-pages"
3-
import type { ReactElement } from "react"
4-
import { useThemeConfig } from "nextra-theme-docs"
5-
import type { DocsThemeConfig } from "nextra-theme-docs"
6-
7-
import { StripesDecoration } from "@/app/conf/_design-system/stripes-decoration"
8-
import { learnPages } from "@/components/learn-aggregator/learn-pages"
9-
10-
import blurCorner from "./blur-corner.webp"
11-
import clsx from "clsx"
12-
13-
interface NavLinkProps {
14-
currentIndex: number
15-
flatDocsDirectories: Item[]
16-
}
17-
18-
export function NavLinks({
19-
flatDocsDirectories,
20-
currentIndex,
21-
}: NavLinkProps): ReactElement | null {
22-
const themeConfig = useThemeConfig()
23-
const nav = themeConfig.navigation
24-
const navigation: Exclude<DocsThemeConfig["navigation"], boolean> =
25-
typeof nav === "boolean" ? { prev: nav, next: nav } : nav
26-
let prev = navigation.prev && flatDocsDirectories[currentIndex - 1]
27-
let next = navigation.next && flatDocsDirectories[currentIndex + 1]
28-
29-
if (prev && !prev.isUnderCurrentDocsTree) prev = false
30-
if (next && !next.isUnderCurrentDocsTree) next = false
31-
32-
if (!prev && !next) return null
33-
34-
const displayPost = next || prev
35-
const isNext = !!next
36-
37-
if (!displayPost) return null
38-
39-
const pageKey = displayPost.route.split("/").pop() as keyof typeof learnPages
40-
const pageData = learnPages[pageKey]
41-
const section = pageData?.section
42-
43-
return (
44-
<div className="gql-container mb-8 print:hidden">
45-
<NextLink
46-
href={displayPost.route}
47-
className="gql-focus-visible relative flex items-center gap-8 border border-neu-200 bg-neu-0 p-8 hover:ring hover:ring-neu-100 dark:border-neu-50 dark:hover:ring-neu-50/50"
48-
>
49-
<div
50-
className={clsx(
51-
"pointer-events-none absolute inset-0 left-4 overflow-hidden",
52-
section === "getting-started" &&
53-
"[--start:var(--color-pri-lightest)] dark:[--start:var(--color-pri-darker)]",
54-
section === "best-practices" &&
55-
"[--start:var(--color-sec-lighter)] dark:[--start:var(--color-sec-darker)]",
56-
)}
57-
style={{
58-
maskImage: `url(${blurCorner.src})`,
59-
WebkitMaskImage: `url(${blurCorner.src})`,
60-
maskSize: "50% 50%",
61-
WebkitMaskSize: "50% 50%",
62-
maskPosition: "top right",
63-
WebkitMaskPosition: "top right",
64-
maskRepeat: "no-repeat",
65-
WebkitMaskRepeat: "no-repeat",
66-
}}
67-
>
68-
<StripesDecoration
69-
oddClassName="bg-[linear-gradient(180deg,hsl(var(--start))_0%,hsl(var(--color-neu-0)/0)_50%)]"
70-
stripeWidth="12px"
71-
/>
72-
</div>
73-
74-
<div className="flex flex-1 flex-col gap-6">
75-
<p className="typography-menu text-pri-base dark:text-pri-light">
76-
{isNext ? "next lesson" : "previous lesson"}
77-
</p>
78-
79-
<div className="flex flex-col gap-4 text-neu-900">
80-
<h2 className="typography-h2">{displayPost.title}</h2>
81-
{pageData?.description && (
82-
<p className="typography-body-lg max-w-[560px]">
83-
{pageData.description}
84-
</p>
85-
)}
86-
</div>
87-
88-
<div className="flex h-12 items-center justify-center self-start bg-neu-900 px-8 py-2">
89-
<span className="typography-button text-neu-0">
90-
Go to {isNext ? "next" : "previous"} lesson
91-
</span>
92-
</div>
93-
</div>
94-
95-
{pageData?.icon && (
96-
<div className="relative flex size-[222px] bg-neu-0">
97-
<div
98-
className={clsx(
99-
"shrink-0 items-center justify-center p-12",
100-
section === "getting-started" &&
101-
"bg-pri-lightest dark:bg-pri-lighter/5",
102-
section === "best-practices" &&
103-
"bg-sec-lighter dark:bg-sec-lighter/10",
104-
)}
105-
>
106-
<img
107-
src={pageData.icon}
108-
alt=""
109-
className="size-full object-contain"
110-
/>
111-
</div>
112-
</div>
113-
)}
114-
</NextLink>
115-
</div>
116-
)
117-
}
1+
export { LearnNavLinkCard } from "./learn-nav-link-card"
2+
export { ArrowNavLinks } from "./arrow-nav-links"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import NextLink from "next/link"
2+
import type { Item } from "nextra/normalize-pages"
3+
import type { ReactElement } from "react"
4+
import { useThemeConfig } from "nextra-theme-docs"
5+
import type { DocsThemeConfig } from "nextra-theme-docs"
6+
7+
import { StripesDecoration } from "@/app/conf/_design-system/stripes-decoration"
8+
import { learnPages } from "@/components/learn-aggregator/learn-pages"
9+
10+
import blurCorner from "./blur-corner.webp"
11+
import clsx from "clsx"
12+
13+
interface LearnNavLinkCardProps {
14+
currentIndex: number
15+
flatDocsDirectories: Item[]
16+
className?: string
17+
}
18+
19+
export function LearnNavLinkCard({
20+
flatDocsDirectories,
21+
currentIndex,
22+
className,
23+
}: LearnNavLinkCardProps): ReactElement | null {
24+
const themeConfig = useThemeConfig()
25+
const nav = themeConfig.navigation
26+
const navigation: Exclude<DocsThemeConfig["navigation"], boolean> =
27+
typeof nav === "boolean" ? { prev: nav, next: nav } : nav
28+
let prev = navigation.prev && flatDocsDirectories[currentIndex - 1]
29+
let next = navigation.next && flatDocsDirectories[currentIndex + 1]
30+
31+
if (prev && !prev.isUnderCurrentDocsTree) prev = false
32+
if (next && !next.isUnderCurrentDocsTree) next = false
33+
34+
if (!prev && !next) return null
35+
36+
const displayPost = next || prev
37+
const isNext = !!next
38+
39+
if (!displayPost) return null
40+
41+
const pageKey = displayPost.route.split("/").pop() as keyof typeof learnPages
42+
const pageData = learnPages[pageKey]
43+
const section = pageData?.section
44+
45+
return (
46+
<div
47+
className={clsx(
48+
"gql-container gql-section bg-neu-0 py-8 lg:py-16 xl:py-20 print:hidden",
49+
className,
50+
)}
51+
>
52+
<NextLink
53+
href={displayPost.route}
54+
className="gql-focus-visible relative mx-auto flex max-w-[1056px] items-center gap-8 border border-neu-200 bg-neu-0 p-8 hover:ring hover:ring-neu-100 dark:border-neu-50 dark:hover:ring-neu-50/50"
55+
>
56+
<div
57+
className={clsx(
58+
"pointer-events-none absolute inset-0 left-4 overflow-hidden",
59+
section === "getting-started" &&
60+
"[--start:var(--color-pri-lightest)] dark:[--start:var(--color-pri-darker)]",
61+
section === "best-practices" &&
62+
"[--start:var(--color-sec-lighter)] dark:[--start:var(--color-sec-darker)]",
63+
)}
64+
style={{
65+
maskImage: `url(${blurCorner.src})`,
66+
WebkitMaskImage: `url(${blurCorner.src})`,
67+
maskSize: "50% 50%",
68+
WebkitMaskSize: "50% 50%",
69+
maskPosition: "top right",
70+
WebkitMaskPosition: "top right",
71+
maskRepeat: "no-repeat",
72+
WebkitMaskRepeat: "no-repeat",
73+
}}
74+
>
75+
<StripesDecoration
76+
oddClassName="bg-[linear-gradient(180deg,hsl(var(--start))_0%,hsl(var(--color-neu-0)/0)_50%)]"
77+
stripeWidth="12px"
78+
/>
79+
</div>
80+
81+
<div className="flex flex-1 flex-col gap-6">
82+
<p className="typography-menu text-pri-base dark:text-pri-light">
83+
{isNext ? "next lesson" : "previous lesson"}
84+
</p>
85+
86+
<div className="flex flex-col gap-4 text-neu-900">
87+
<h2 className="typography-h2">{displayPost.title}</h2>
88+
{pageData?.description && (
89+
<p className="typography-body-lg max-w-[560px]">
90+
{pageData.description}
91+
</p>
92+
)}
93+
</div>
94+
95+
<div className="flex h-12 items-center justify-center self-start bg-neu-900 px-8 py-2">
96+
<span className="typography-button text-neu-0">
97+
Go to {isNext ? "next" : "previous"} lesson
98+
</span>
99+
</div>
100+
</div>
101+
102+
{pageData?.icon && (
103+
<div className="relative flex size-[222px] bg-neu-0">
104+
<div
105+
className={clsx(
106+
"shrink-0 items-center justify-center p-12",
107+
section === "getting-started" &&
108+
"bg-pri-lightest dark:bg-pri-lighter/5",
109+
section === "best-practices" &&
110+
"bg-sec-lighter dark:bg-sec-lighter/10",
111+
)}
112+
>
113+
<img
114+
src={pageData.icon}
115+
alt=""
116+
className="size-full object-contain"
117+
/>
118+
</div>
119+
</div>
120+
)}
121+
</NextLink>
122+
</div>
123+
)
124+
}

0 commit comments

Comments
 (0)