site-config.ts3.3 KBView on GitHub const TITLE = 'Cedar — The AI-native workspace for mid-funnel sales';
const DESCRIPTION =
'Cedar analyses your sales calls, email and CRM to map out a winning playbook — then drafts the context-aware follow-ups that keep every deal moving.';
/**
* Origin the marketing pages present as canonical to search engines.
*
* Defaults to the app origin so nothing changes until the marketing site actually
* answers on its own domain — pointing `rel=canonical` at a host that 301s straight
* back here would be a canonical loop. Set VITE_PUBLIC_MARKETING_URL to
* https://cedarcopilot.com in the frontend build once apex DNS is cut over.
*/
export const CANONICAL_ORIGIN: string = (import.meta.env.VITE_PUBLIC_MARKETING_URL ||
import.meta.env.VITE_PUBLIC_APP_URL) as string;
/**
* Absolute canonical URL for a path on the marketing origin.
*
* Root's `meta` is what every route without its own `meta` export inherits — React Router
* does not merge meta up the tree — so a canonical fixed at the bare origin would tell
* crawlers that `/pricing`, `/legal/*`, `/roadmap` and `/hr` are all duplicates of the
* homepage. Build it from the path the visitor is actually on.
*/
export function canonicalUrl(pathname: string): string {
try {
return new URL(pathname, CANONICAL_ORIGIN).toString();
} catch {
return CANONICAL_ORIGIN;
}
}
export const siteConfig = {
title: TITLE,
description: DESCRIPTION,
applicationName: 'Cedar',
openGraph: {
title: TITLE,
description: DESCRIPTION,
images: [
{
url: `${import.meta.env.VITE_PUBLIC_APP_URL}/og.png`,
width: 1200,
height: 630,
alt: TITLE,
},
],
},
alternates: {
canonical: CANONICAL_ORIGIN,
},
};
type FaviconLink = {
tagName: 'link';
rel: string;
href: string;
type?: string;
sizes?: string;
};
/**
* The site-wide tab/bookmark icons.
*
* These are meta descriptors rather than static `<link>` tags in root's `<head>` so that a route
* with its own `meta` export still gets them — React Router replaces a route's meta wholesale
* instead of merging it, so anything a route needs has to be in its own return value.
*
* `apple-touch-icon` is what iOS uses when the page is saved to the home screen.
*/
export function faviconLinks(): FaviconLink[] {
return [
{
tagName: 'link',
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/icons/favicon-32x32.png',
},
{
tagName: 'link',
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/icons/favicon-16x16.png',
},
{ tagName: 'link', rel: 'icon', href: '/favicon.ico', sizes: 'any' },
{ tagName: 'link', rel: 'apple-touch-icon', href: '/icons/apple-touch-icon.png' },
];
}
/** Days the calendar icons cover — one file per day of the month, as Google Calendar does. */
export const CALENDAR_ICON_DAYS = 31;
/**
* The calendar tab icon showing `day`, generated by scripts/generate-calendar-favicons.mjs.
*
* Out-of-range days clamp rather than 404, so a bad clock or a caller doing its own date maths
* still gets an icon.
*/
export function calendarDayIconHref(day: number): string {
const clamped = Math.min(Math.max(Math.trunc(day) || 1, 1), CALENDAR_ICON_DAYS);
return `/icons/calendar/day-${clamped}.svg`;
}