import { previewTemplate } from '../../lib/seo/template-preview'; import type { SeoEditorEnv } from '../env'; import type { EditedPost } from '../hooks/use-seo-meta'; /** What the variables resolve to for this post, term or author right now. */ export interface LiveValues { post: EditedPost; keyword: string; primaryTerm: string; firstTerm: string; } const textOf = (html: string): string => html .replace(//g, ' ') .replace(/<[^>]+>/g, ' ') .replace(/ /g, ' ') .replace(/\s+/g, ' ') .trim(); /** Characters of an automatic excerpt, as the server cuts it. */ const EXCERPT_LENGTH = 145; /** * The excerpt, or the start of the content, cut the way the server cuts * it: at a word, with an ellipsis, inside the 920 pixels Google shows. */ export const excerptOf = (post: EditedPost): string => { // The text without its headings, as the server reads it. const body = textOf( post.content.replace(/]*>[\s\S]*?<\/h[1-6]>/gi, ' ') ); const source = (post.excerpt.trim() ? textOf(post.excerpt) : '') || body || textOf(post.content); if (source.length <= EXCERPT_LENGTH) { return source; } let cut = source.slice(0, EXCERPT_LENGTH); const space = cut.lastIndexOf(' '); if (space > 60) { cut = cut.slice(0, space); } return `${cut.replace(/[\s,;:.\-–—]+$/, '')}…`; }; /** * A title or description template rendered for the object in the editor, * with the server's examples standing in for what only the server knows. */ export const renderTemplate = ( template: string, env: SeoEditorEnv, live: LiveValues ): string => { const now = new Date(); const values: Record = { '%title%': live.post.title, '%excerpt%': env.object === 'user' ? '' : excerptOf(live.post), '%focuskw%': live.keyword, '%category%': live.firstTerm, '%primary_category%': live.primaryTerm || live.firstTerm, '%pt_single%': env.object === 'post' ? env.typeLabel : '', '%term%': env.object === 'term' ? live.post.title : '', '%term_description%': env.object === 'term' ? textOf(live.post.excerpt) : '', '%page%': '', '%currentyear%': String(now.getFullYear()), '%currentdate%': now.toLocaleDateString(), '%date%': now.toLocaleDateString(), }; if (env.object === 'user') { values['%author%'] = live.post.title; } const variables = env.variables.map(variable => ({ ...variable, example: variable.name in values ? values[variable.name] : variable.example, })); return previewTemplate(template, variables, env.separator); };