import { addIcons, iconHtml } from 'vanilla-jui'
import icons from '../config/icons.ts'
import { joinLocalePath, localize, pageWithoutLocale } from '../runtime/i18n.ts'
import { normalizeRel } from '../runtime/path.ts'
import type {
DocI18n,
LocaleEntry,
NavItem,
RuntimeConfig,
RuntimePage,
} from '../types.ts'
import { isPrevNextEnabled } from './features.ts'
import { escapeHtml } from './html.ts'
import { relativeAsset } from './path.ts'
import { toText } from './string.ts'
addIcons(icons)
type PrevNextDirection = 'prev' | 'next'
interface PrevNextItem {
rel: string
title: string
}
function rawItemPath(item: NavItem = {}): unknown {
return item.path ?? item.href ?? item.url ?? ''
}
function isExternalPath(value: unknown = ''): boolean {
const itemPath = toText(value)
return (
/^(?:[a-z][a-z\d+.-]*:)?\/\//i.test(itemPath) || itemPath.startsWith('#')
)
}
function normalizePagePath(value: unknown = ''): string {
const itemPath = toText(value).trim()
if (!itemPath || isExternalPath(itemPath)) return ''
const clean = itemPath.replace(/^\/+/, '')
if (clean.endsWith('/')) return `${clean}index.html`
if (/\.[a-z0-9]+$/i.test(clean)) return clean
return `${clean}.html`
}
function flattenItems(
items: NavItem[],
i18n: DocI18n,
result: PrevNextItem[] = []
): PrevNextItem[] {
for (const item of items) {
const rel = normalizePagePath(rawItemPath(item))
if (rel) {
result.push({
rel,
title: localize(item.i18n || item.label || item.title, i18n),
})
}
if (Array.isArray(item.children)) {
flattenItems(item.children, i18n, result)
}
}
return result
}
function translate(key: string, fallback: string, i18n: DocI18n): string {
const text = localize(key, i18n)
return text && text !== key ? text : fallback
}
function renderLink(
item: PrevNextItem,
page: RuntimePage,
locale: LocaleEntry | null,
direction: PrevNextDirection,
i18n: DocI18n
): string {
const href = relativeAsset(
page.rel || 'index.html',
locale ? joinLocalePath(locale, item.rel) : item.rel
)
const label =
direction === 'prev'
? translate('prevNext.previous', 'Previous', i18n)
: translate('prevNext.next', 'Next', i18n)
const icon = iconHtml(
direction === 'prev' ? 'arrow-left' : 'arrow-right'
).replace('