46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
|
|
export const SITE_URL = 'https://queuenorth.com'
|
||
|
|
|
||
|
|
// Sitewide search/entity anchor. Referenced by the Organization entity on Home.
|
||
|
|
export const websiteLd = {
|
||
|
|
'@context': 'https://schema.org',
|
||
|
|
'@type': 'WebSite',
|
||
|
|
'@id': `${SITE_URL}/#website`,
|
||
|
|
url: SITE_URL,
|
||
|
|
name: 'Queue North Technologies',
|
||
|
|
publisher: { '@id': `${SITE_URL}/#organization` },
|
||
|
|
inLanguage: 'en-US',
|
||
|
|
}
|
||
|
|
|
||
|
|
const MAX_DESCRIPTION = 158
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Joins description fragments and trims to what search engines actually display,
|
||
|
|
* cutting on a word boundary rather than mid-word.
|
||
|
|
* @param {...string} parts
|
||
|
|
*/
|
||
|
|
export const clampDescription = (...parts) => {
|
||
|
|
const text = parts.filter(Boolean).join(' ').replace(/\s+/g, ' ').trim()
|
||
|
|
if (text.length <= MAX_DESCRIPTION) return text
|
||
|
|
|
||
|
|
const cut = text.slice(0, MAX_DESCRIPTION)
|
||
|
|
return `${cut.slice(0, cut.lastIndexOf(' ')).replace(/[,;:.]$/, '')}…`
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Builds a BreadcrumbList for a page's position in the site hierarchy.
|
||
|
|
* @param {Array<{name: string, path: string}>} trail ordered from the site root
|
||
|
|
*/
|
||
|
|
export const buildBreadcrumbLd = (trail) => ({
|
||
|
|
'@context': 'https://schema.org',
|
||
|
|
'@type': 'BreadcrumbList',
|
||
|
|
itemListElement: [
|
||
|
|
{ name: 'Home', path: '/' },
|
||
|
|
...trail,
|
||
|
|
].map((crumb, index) => ({
|
||
|
|
'@type': 'ListItem',
|
||
|
|
position: index + 1,
|
||
|
|
name: crumb.name,
|
||
|
|
item: `${SITE_URL}${crumb.path === '/' ? '' : crumb.path}`,
|
||
|
|
})),
|
||
|
|
})
|