Skip to content

Instantly share code, notes, and snippets.

@ndimatteo
Last active March 28, 2024 04:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndimatteo/dbecb6cb9b5f81acff36a34f2b495fb7 to your computer and use it in GitHub Desktop.
Save ndimatteo/dbecb6cb9b5f81acff36a34f2b495fb7 to your computer and use it in GitHub Desktop.
Advanced Link Component for Next.js
export const getRoute = ({ type, slug, hash, query }) => {
// append static base paths based on the page type
const basePath = {
recipe: 'recipe',
project: 'work',
}[type]
// combine our base path with the slug
const routePath = [basePath, slug].filter(Boolean).join('/')
// construct the hash fragment if one exists
const hashFragment = hash ? `#${hash}` : ''
// construct the query string if one exists
const queryString = query
? `?${Object.keys(query)
.map((key) => `${key}=${query[key]}`)
.join('&')}`
: ''
// return the full route path
return `/${routePath}${queryString}${hashFragment}`
}
// conditionally wrap a component with another
export const ConditionalWrapper = ({ condition, wrapper, children }) => {
return condition ? wrapper(children) : children
}
import React from 'react'
const Example = () => {
return (
<>
<Link href="/relative-string">Internal Page (string)</Link>
<Link href={{
type: 'page',
slug: 'spaghetti',
hash: 'parmesan',
query: {
noodles: 'linguine',
sauce: 'bolognese'
}
}}>Internal Page (object)</Link>
<Link href="mailto:hello@spaghetti.com">External URL (mailto:)</Link>
<Link href="tel:800-311-0932">External URL (tel:)</Link>
<Link href="https://nextjs.org">External URL</Link>
</>
)
}
export default Example
import customLink from '@lib/custom-link'
export default {
title: 'Navigation',
name: 'navigation',
type: 'object',
fields: [
{
title: 'Links',
name: 'links',
type: 'array',
of: [
customLink({
internal: true
}),
customLink()
]
},
{
title: 'Call To Action',
name: 'cta',
type: 'array',
description: 'Link this card (optional)',
of: [
customLink({
internal: true,
hasDisplayTitle: false,
}),
customLink({
hasDisplayTitle: false,
}),
],
validation: (Rule) => Rule.length(1).error('You can only have one CTA'),
}
],
}
export const page = groq`
"type": _type,
"slug": slug.current,
hash
`
// Construct our "link" GROQ
export const link = groq`
_key,
"type": _type,
page->{
${page},
},
url,
title,
label
`
import React from 'react'
import Link from '@components/link'
const Navigation = ({ links }) => {
return (
<ul>
{links.map(({ type, page, url, title }, key) => {
// construct our href value based on the link type
const href = {
external: url,
internal: page,
}[type]
return (
<li key={key}>
<Link href={href} external={type === 'external'}>
{title}
</Link>
</li>
)
})}
</ul>
)
}
export default Navigation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment