add images and redesign hompeage into sections, fix the dark color
Build & Deploy / Build & Push Docker Image (push) Failing after 48s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m2s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s

This commit is contained in:
root
2026-06-26 21:01:02 -04:00
parent d7fb7b7a7b
commit 35172ab46b
102 changed files with 1106 additions and 280 deletions
+100 -3
View File
@@ -1,16 +1,21 @@
import type { ApprovedIconName } from '@/components/foundation/Icon';
import type { PreviewRow } from '@/components/marketing/ProductPreview';
import type { HomepageMessages, ShellMessages } from '@/lib/localization/messages';
import type { Locale } from '@/lib/localization/config';
import { accountCreateUrl } from '@/lib/account-urls';
import {
fleetBandIds,
pricingPlanIds,
type FleetBandId,
type PricingPlanId,
} from '@/content/pricing-config';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
export interface HomepageAction {
label: string;
disabledReason: string;
href?: string;
disabledReason?: string;
}
export interface TitledDescription {
@@ -43,6 +48,13 @@ export interface HomepagePricingPlan {
cta: string;
}
export interface HomepageImageAsset {
src: string;
alt: string;
width: number;
height: number;
}
export interface HomepageContent {
hero: {
eyebrow: string;
@@ -56,6 +68,7 @@ export interface HomepageContent {
illustrativeLabel: string;
rows: PreviewRow[];
};
image: HomepageImageAsset;
};
trust: {
eyebrow: string;
@@ -71,12 +84,14 @@ export interface HomepageContent {
beforeItems: string[];
afterTitle: string;
afterItems: string[];
image: HomepageImageAsset;
};
workflow: {
eyebrow: string;
title: string;
body: string;
steps: HomepageWorkflowStep[];
image: HomepageImageAsset;
};
roles: {
eyebrow: string;
@@ -88,6 +103,7 @@ export interface HomepageContent {
title: string;
body: string;
items: TitledDescription[];
image: HomepageImageAsset;
};
results: {
eyebrow: string;
@@ -96,6 +112,7 @@ export interface HomepageContent {
metrics: TitledDescription[];
methodTitle: string;
method: string[];
image: HomepageImageAsset;
};
integrations: {
eyebrow: string;
@@ -147,6 +164,7 @@ export interface HomepageContent {
body: string;
primary: HomepageAction;
secondary: HomepageAction;
image: HomepageImageAsset;
};
}
@@ -156,6 +174,42 @@ const moduleIcons: ApprovedIconName[] = ['calendar', 'car', 'check', 'search', '
const resultIcons: ApprovedIconName[] = ['calendar', 'settings', 'car', 'warning'];
const securityIcons: ApprovedIconName[] = ['settings', 'search', 'globe', 'warning'];
const homepagePublicPath = join(process.cwd(), 'public');
const homepagePublicFallbackPath = join(process.cwd(), 'apps/homepage/public');
const localeAssetSuffix: Record<Locale, string> = {
en: 'EN',
fr: 'FR',
ar: 'AR',
};
function publicAssetExists(fileName: string): boolean {
return existsSync(join(homepagePublicPath, fileName)) || existsSync(join(homepagePublicFallbackPath, fileName));
}
function localizedImage(
subject: string,
locale: Locale,
extension: 'jpeg' | 'png',
dimensions: Pick<HomepageImageAsset, 'width' | 'height'>,
alt: string,
): HomepageImageAsset {
const localizedFile = `${subject}_${localeAssetSuffix[locale]}.${extension}`;
const hyphenLocalizedFile = `${subject}-${locale}.${extension}`;
const defaultFile = `${subject}.${extension}`;
const fileName = publicAssetExists(localizedFile)
? localizedFile
: publicAssetExists(hyphenLocalizedFile)
? hyphenLocalizedFile
: defaultFile;
return {
src: `/${fileName}`,
alt,
width: dimensions.width,
height: dimensions.height,
};
}
function pair(value: readonly string[], context: string): { title: string; description: string } {
const title = value[0];
const description = value[1];
@@ -211,6 +265,7 @@ function mapPairs(
export function buildHomepageContent(
homepage: HomepageMessages,
shell: ShellMessages,
locale: Locale = 'en',
): HomepageContent {
const pendingReason = shell.states.pendingBody;
@@ -219,7 +274,7 @@ export function buildHomepageContent(
eyebrow: homepage.hero.eyebrow,
title: homepage.hero.title,
body: homepage.hero.body,
primary: { label: homepage.hero.primary, disabledReason: shell.header.demoUnavailable },
primary: { label: homepage.hero.primary, href: accountCreateUrl(locale) },
secondary: { label: homepage.hero.secondary, disabledReason: pendingReason },
preview: {
title: homepage.preview.title,
@@ -242,6 +297,13 @@ export function buildHomepageContent(
},
],
},
image: localizedImage(
'dashboard1',
locale,
'png',
{ width: 1672, height: 941 },
homepage.preview.title,
),
},
trust: {
eyebrow: homepage.trust.eyebrow,
@@ -257,6 +319,13 @@ export function buildHomepageContent(
beforeItems: homepage.comparison.beforeItems,
afterTitle: homepage.comparison.afterTitle,
afterItems: homepage.comparison.afterItems,
image: localizedImage(
'benefit1',
locale,
'png',
{ width: 1672, height: 941 },
homepage.comparison.title,
),
},
workflow: {
eyebrow: homepage.workflow.eyebrow,
@@ -266,6 +335,13 @@ export function buildHomepageContent(
id: `workflow-${index + 1}`,
...triple(value, `workflow.steps[${index}]`),
})),
image: localizedImage(
'workflow1',
locale,
'png',
{ width: 1672, height: 941 },
homepage.workflow.title,
),
},
roles: {
eyebrow: homepage.roles.eyebrow,
@@ -277,6 +353,13 @@ export function buildHomepageContent(
title: homepage.modules.title,
body: homepage.modules.body,
items: mapPairs(homepage.modules.items, 'module', moduleIcons),
image: localizedImage(
'oilchange1',
locale,
'png',
{ width: 1254, height: 1254 },
homepage.modules.title,
),
},
results: {
eyebrow: homepage.results.eyebrow,
@@ -285,6 +368,13 @@ export function buildHomepageContent(
metrics: mapPairs(homepage.results.metrics, 'measurement', resultIcons),
methodTitle: homepage.results.methodTitle,
method: homepage.results.method,
image: localizedImage(
'dashboard2',
locale,
'png',
{ width: 1672, height: 941 },
homepage.results.title,
),
},
integrations: {
eyebrow: homepage.integrations.eyebrow,
@@ -346,8 +436,15 @@ export function buildHomepageContent(
eyebrow: homepage.final.eyebrow,
title: homepage.final.title,
body: homepage.final.body,
primary: { label: homepage.final.primary, disabledReason: shell.header.demoUnavailable },
primary: { label: homepage.final.primary, href: accountCreateUrl(locale) },
secondary: { label: homepage.final.secondary, disabledReason: pendingReason },
image: localizedImage(
'rentaldrivego',
locale,
'jpeg',
{ width: 1220, height: 1167 },
'RentalDriveGo',
),
},
};
}