vite-pages-theme-doc
Version:
A document theme for vite-plugin-react-pages.
151 lines (141 loc) • 4.54 kB
text/typescript
import type { I18nConfig, LocalConfig } from '.'
import { ensureStartSlash, getStaticDataValue, removeStartSlash } from './utils'
// map groups -> subgroups -> pages
export type PageGroups = {
[groupKey: string]: {
[subGroupKey: string]: PageMeta[]
}
}
export type PageMeta = {
pageStaticData: any
// pagePath is parsed into three part:
// /${groupKey}/${subGroupKey}/${pageKeyInGroup}
pagePath: string
groupKey: string
subGroupKey: string
pageKeyInGroup: string
// pageTitle is extracted from frontmatter or markdown title
// use pageKeyInGroup as fallback
pageTitle: string
pageLocale: LocalConfig | undefined
pageLocaleKey: string | undefined
}
export function getPageGroups(staticData: any, i18n: I18nConfig | undefined) {
const groups: PageGroups = {}
function ensureGroup(group: string): Record<string, PageMeta[]>
function ensureGroup(group: string, subGroup: string): PageMeta[]
function ensureGroup(group: string, subGroup?: string) {
const subGroups = (groups[group] ||= {})
if (!subGroup) return subGroups
return (subGroups[subGroup] ||= [])
}
Object.entries(staticData).forEach(([pagePath, pageStaticData]) => {
if (pagePath === '/404') return
const pageInfo = analyzePageInfo(pagePath, pageStaticData, i18n)
ensureGroup(pageInfo.group, pageInfo.subGroup).push({
pageStaticData,
pagePath,
groupKey: pageInfo.group,
subGroupKey: pageInfo.subGroup,
pageKeyInGroup: pageInfo.pageKeyInGroup,
pageTitle: pageInfo.pageTitle,
pageLocale: pageInfo.locale,
pageLocaleKey: pageInfo.localeKey,
})
})
const rootGroup = groups['/']?.['/']
if (rootGroup) {
const filtered = rootGroup.filter((page) => {
if (page.pageKeyInGroup === '/') return true
if (groups[page.pageKeyInGroup]) {
// it is explicit grouped
if (getStaticDataValue(page.pageStaticData, 'group')) return true
// if there is also pages like /guide/start
// then /guide should not be grouped with /faq
// instead, /guide should be moved to the "guide" group
ensureGroup(page.pageKeyInGroup, '/').push(page)
return false
}
return true
})
groups['/']['/'] = filtered
}
return groups
}
export function analyzePageInfo(
pagePath: string,
pageStaticData: any,
i18n: I18nConfig | undefined
): {
group: string
subGroup: string
pageKeyInGroup: string
pageTitle: string
locale: LocalConfig | undefined
localeKey: string | undefined
} {
if (!pagePath.startsWith('/'))
throw new Error(`expect pagePath.startsWith('/'). pagePath: ${pagePath}`)
const { pagePathWithoutLocalePrefix, locale, localeKey } =
matchPagePathLocalePrefix(pagePath, i18n)
const seg = removeStartSlash(pagePathWithoutLocalePrefix).split('/')
let group: string = getStaticDataValue(pageStaticData, 'group')
let subGroup: string = getStaticDataValue(pageStaticData, 'subGroup')
// used as default title
const pageKeyInGroup: string = seg[seg.length - 1] || '/'
if (seg.length === 1) {
group ||= '/'
subGroup ||= '/'
} else if (seg.length === 2) {
group ||= seg[0]
subGroup ||= '/'
} else if (seg.length >= 3) {
group ||= seg[0]
subGroup ||= seg[1]
} else {
throw new Error('getPageGroup assertion fail')
}
return {
group,
subGroup,
pageKeyInGroup,
pageTitle: getStaticDataValue(pageStaticData, 'title') ?? pageKeyInGroup,
locale,
localeKey,
}
}
export function matchPagePathLocalePrefix(
pagePath: string,
i18n: I18nConfig | undefined
) {
const result = {
pagePathWithoutLocalePrefix: pagePath,
localeKey: undefined as string | undefined,
locale: undefined as LocalConfig | undefined,
}
if (!i18n?.locales) return result
Object.entries(i18n.locales).forEach(([localeKey, locale]) => {
const prefix = locale.routePrefix || ensureStartSlash(localeKey)
if (
pagePath.startsWith(prefix) &&
// routePrefix '/' has lower priority than '/any-prefix'
(!result.locale || result.locale.routePrefix === '/')
) {
result.pagePathWithoutLocalePrefix = ensureStartSlash(
pagePath.slice(prefix.length)
)
result.localeKey = localeKey
result.locale = locale
}
})
// fallback to defaultLocale
if (
!result.locale &&
i18n.defaultLocale &&
i18n.locales[i18n.defaultLocale]
) {
result.localeKey = i18n.defaultLocale
result.locale = i18n.locales[i18n.defaultLocale]
}
return result
}