206 lines
7.2 KiB
TypeScript
206 lines
7.2 KiB
TypeScript
import type {
|
|
CtaLink,
|
|
FooterLead,
|
|
FooterNavigationGroup,
|
|
NavigationItem,
|
|
PageDefinition,
|
|
PageFamily,
|
|
ShellTone,
|
|
SiteMetadata,
|
|
SitePath,
|
|
VisualFoundationContract,
|
|
} from '@/types/site';
|
|
|
|
export const siteMetadata: SiteMetadata = {
|
|
siteName: 'TenantAtlas',
|
|
siteTagline: 'Governance of record for Microsoft tenant operations.',
|
|
siteDescription:
|
|
'TenantAtlas helps MSP and enterprise teams keep Microsoft tenant change history observable, reviewable, and safer to operate.',
|
|
siteUrl: import.meta.env.PUBLIC_SITE_URL ?? 'https://tenantatlas.example',
|
|
};
|
|
|
|
export const visualFoundationContract: VisualFoundationContract = {
|
|
pageFamilies: ['landing', 'trust', 'content'],
|
|
ctaHierarchy: ['primary', 'secondary', 'ghost'],
|
|
requiredColorRoles: [
|
|
'background',
|
|
'foreground',
|
|
'muted',
|
|
'muted-foreground',
|
|
'card',
|
|
'card-foreground',
|
|
'border',
|
|
'input',
|
|
'primary',
|
|
'primary-foreground',
|
|
'secondary',
|
|
'secondary-foreground',
|
|
'accent',
|
|
'accent-foreground',
|
|
'success',
|
|
'warning',
|
|
'destructive',
|
|
'info',
|
|
],
|
|
accessibilityBaseline: [
|
|
'focus-visible',
|
|
'readable-contrast',
|
|
'non-color-only-semantics',
|
|
'navigation-vs-cta-differentiation',
|
|
'mobile-readable-density',
|
|
],
|
|
surfaceLayers: ['page-background', 'default-content', 'card', 'elevated', 'muted-inset', 'highlighted'],
|
|
};
|
|
|
|
export const primaryNavigation: NavigationItem[] = [
|
|
{ href: '/product', label: 'Product', description: 'Understand the operating model.' },
|
|
{ href: '/solutions', label: 'Solutions', description: 'See the fit for MSP and enterprise teams.' },
|
|
{ href: '/security-trust', label: 'Security & Trust', description: 'Review the product posture.' },
|
|
{ href: '/integrations', label: 'Integrations', description: 'Inspect the real ecosystem fit.' },
|
|
{ href: '/contact', label: 'Contact', description: 'Reach the team for a working session.' },
|
|
];
|
|
|
|
export const footerNavigationGroups: FooterNavigationGroup[] = [
|
|
{
|
|
title: 'Explore',
|
|
items: [
|
|
{ href: '/', label: 'Home' },
|
|
{ href: '/product', label: 'Product' },
|
|
{ href: '/solutions', label: 'Solutions' },
|
|
{ href: '/security-trust', label: 'Security & Trust' },
|
|
{ href: '/integrations', label: 'Integrations' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Next step',
|
|
items: [
|
|
{ href: '/contact', label: 'Contact / Demo' },
|
|
{ href: '/legal', label: 'Legal' },
|
|
],
|
|
},
|
|
{
|
|
title: 'Legal',
|
|
items: [
|
|
{ href: '/privacy', label: 'Privacy' },
|
|
{ href: '/terms', label: 'Terms' },
|
|
],
|
|
},
|
|
];
|
|
|
|
export const contactCta: CtaLink = {
|
|
href: '/contact',
|
|
label: 'Request a working session',
|
|
helper: 'Bring your governance questions, rollout concerns, or evaluation goals.',
|
|
variant: 'primary',
|
|
};
|
|
|
|
const footerLeadByFamily: Record<PageFamily, FooterLead> = {
|
|
landing: {
|
|
eyebrow: 'Keep the next move obvious',
|
|
title: 'A calmer public surface should still lead somewhere concrete.',
|
|
description:
|
|
'Landing pages should move visitors from orientation into a product, trust, or contact path without competing CTAs or dead ends.',
|
|
intent: 'conversion',
|
|
primaryCta: contactCta,
|
|
},
|
|
trust: {
|
|
eyebrow: 'Trust stays actionable',
|
|
title: 'Security, legal, and contact paths should reinforce one another.',
|
|
description:
|
|
'Trust-oriented pages should keep legal context, product posture, and the working-session route connected instead of turning caution into friction.',
|
|
intent: 'guidance',
|
|
primaryCta: {
|
|
href: '/contact',
|
|
label: 'Discuss trust requirements',
|
|
helper: 'Bring current review, legal, or rollout questions into one working conversation.',
|
|
variant: 'primary',
|
|
},
|
|
},
|
|
content: {
|
|
eyebrow: 'Reading should still progress',
|
|
title: 'Long-form pages need the same action hierarchy as landing pages.',
|
|
description:
|
|
'Contact, legal, privacy, and terms routes should feel deliberate and connected to the evaluation path instead of behaving like detached documents.',
|
|
intent: 'legal',
|
|
primaryCta: {
|
|
href: '/contact',
|
|
label: 'Continue the evaluation path',
|
|
helper: 'Move from the reading surface back into a product or trust conversation.',
|
|
variant: 'primary',
|
|
},
|
|
},
|
|
};
|
|
|
|
const headerCtaByFamily: Record<PageFamily, CtaLink> = {
|
|
landing: {
|
|
href: '/contact',
|
|
label: 'Request a working session',
|
|
helper: 'Bring your governance questions, rollout concerns, or evaluation goals.',
|
|
variant: 'secondary',
|
|
},
|
|
trust: {
|
|
href: '/contact',
|
|
label: 'Discuss trust requirements',
|
|
helper: 'Route trust, legal, or rollout questions into one conversation.',
|
|
variant: 'secondary',
|
|
},
|
|
content: {
|
|
href: '/contact',
|
|
label: 'Start the working session',
|
|
helper: 'Turn the reading path into a concrete next step.',
|
|
variant: 'secondary',
|
|
},
|
|
};
|
|
|
|
export const pageDefinitions: Record<SitePath, PageDefinition> = {
|
|
'/': { path: '/', pageRole: 'home', family: 'landing', shellTone: 'brand' },
|
|
'/product': { path: '/product', pageRole: 'product', family: 'landing', shellTone: 'brand' },
|
|
'/solutions': { path: '/solutions', pageRole: 'solutions', family: 'landing', shellTone: 'brand' },
|
|
'/security-trust': { path: '/security-trust', pageRole: 'trust', family: 'trust', shellTone: 'trust' },
|
|
'/integrations': { path: '/integrations', pageRole: 'integrations', family: 'landing', shellTone: 'neutral' },
|
|
'/contact': { path: '/contact', pageRole: 'contact', family: 'content', shellTone: 'neutral' },
|
|
'/legal': { path: '/legal', pageRole: 'legal', family: 'trust', shellTone: 'trust' },
|
|
'/privacy': { path: '/privacy', pageRole: 'privacy', family: 'content', shellTone: 'neutral' },
|
|
'/terms': { path: '/terms', pageRole: 'terms', family: 'content', shellTone: 'neutral' },
|
|
};
|
|
|
|
export const coreRoutes = Object.keys(pageDefinitions) as SitePath[];
|
|
|
|
export function getPageDefinition(path: string): PageDefinition {
|
|
return pageDefinitions[path as SitePath] ?? pageDefinitions['/'];
|
|
}
|
|
|
|
export function getPageFamily(path: string): PageFamily {
|
|
return getPageDefinition(path).family;
|
|
}
|
|
|
|
export function getShellTone(path: string): ShellTone {
|
|
return getPageDefinition(path).shellTone;
|
|
}
|
|
|
|
export function getHeaderCta(path: string): CtaLink {
|
|
const definition = getPageDefinition(path);
|
|
|
|
return {
|
|
...headerCtaByFamily[definition.family],
|
|
...definition.headerCta,
|
|
};
|
|
}
|
|
|
|
export function getFooterLead(path: string): FooterLead {
|
|
const definition = getPageDefinition(path);
|
|
|
|
return {
|
|
...footerLeadByFamily[definition.family],
|
|
...definition.footerLead,
|
|
};
|
|
}
|
|
|
|
export function isActiveNavigationPath(currentPath: string, href: string): boolean {
|
|
if (href === '/') {
|
|
return currentPath === '/';
|
|
}
|
|
|
|
return currentPath === href || currentPath.startsWith(`${href}/`);
|
|
}
|