Files
med-notes/.pnpm-store/v10/files/f1/a063dc43ae7cfff1b603f3714c0a2435aa8d6c00bb1082ed7035468b51d8b45b8c520311596eab31288e77342060380a107dcfea06f72992aef32cf8a471bf
2025-05-09 05:30:08 +02:00

152 lines
3.5 KiB
Plaintext

import * as React from 'react'
import { Asset } from './Asset'
import { useRouter } from './useRouter'
import { useRouterState } from './useRouterState'
import type { RouterManagedTag } from '@tanstack/router-core'
export const useTags = () => {
const router = useRouter()
const routeMeta = useRouterState({
select: (state) => {
return state.matches.map((match) => match.meta!).filter(Boolean)
},
})
const meta: Array<RouterManagedTag> = React.useMemo(() => {
const resultMeta: Array<RouterManagedTag> = []
const metaByAttribute: Record<string, true> = {}
let title: RouterManagedTag | undefined
;[...routeMeta].reverse().forEach((metas) => {
;[...metas].reverse().forEach((m) => {
if (!m) return
if (m.title) {
if (!title) {
title = {
tag: 'title',
children: m.title,
}
}
} else {
const attribute = m.name ?? m.property
if (attribute) {
if (metaByAttribute[attribute]) {
return
} else {
metaByAttribute[attribute] = true
}
}
resultMeta.push({
tag: 'meta',
attrs: {
...m,
},
})
}
})
})
if (title) {
resultMeta.push(title)
}
resultMeta.reverse()
return resultMeta
}, [routeMeta])
const links = useRouterState({
select: (state) =>
state.matches
.map((match) => match.links!)
.filter(Boolean)
.flat(1)
.map((link) => ({
tag: 'link',
attrs: {
...link,
},
})) as Array<RouterManagedTag>,
structuralSharing: true as any,
})
const preloadMeta = useRouterState({
select: (state) => {
const preloadMeta: Array<RouterManagedTag> = []
state.matches
.map((match) => router.looseRoutesById[match.routeId]!)
.forEach((route) =>
router.ssr?.manifest?.routes[route.id]?.preloads
?.filter(Boolean)
.forEach((preload) => {
preloadMeta.push({
tag: 'link',
attrs: {
rel: 'modulepreload',
href: preload,
},
})
}),
)
return preloadMeta
},
structuralSharing: true as any,
})
const headScripts = useRouterState({
select: (state) =>
(
state.matches
.map((match) => match.headScripts!)
.flat(1)
.filter(Boolean) as Array<RouterManagedTag>
).map(({ children, ...script }) => ({
tag: 'script',
attrs: {
...script,
},
children,
})),
structuralSharing: true as any,
})
return uniqBy(
[
...meta,
...preloadMeta,
...links,
...headScripts,
] as Array<RouterManagedTag>,
(d) => {
return JSON.stringify(d)
},
)
}
/**
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
* It should be rendered in the `<head>` of your document.
*/
export function HeadContent() {
const tags = useTags()
return tags.map((tag) => (
<Asset {...tag} key={`tsr-meta-${JSON.stringify(tag)}`} />
))
}
function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {
const seen = new Set<string>()
return arr.filter((item) => {
const key = fn(item)
if (seen.has(key)) {
return false
}
seen.add(key)
return true
})
}