Skip to content

Commit c2f65d8

Browse files
anuveyatsuclaude
andauthored
Update home page message (#1447)
* Update tagline and subtitle so that it is not just about open data. * Update subtitle to be more human-centered. * Update features section with actual framework features rather than cloud (managed) option features. * Add CTA and update message to be more generic. * Fix analytics tracking to ensure events are sent before navigation Update ButtonLink component to use gtag event_callback and fallback timeout to prevent analytics event loss during navigation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Respect modified/new-tab/download clicks in ButtonLink component Only intercept normal left clicks for analytics tracking, allowing Cmd/Ctrl+click, middle-click, target="_blank", and download behavior to work normally. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 0b5053d commit c2f65d8

File tree

4 files changed

+104
-23
lines changed

4 files changed

+104
-23
lines changed

site/components/ButtonLink.tsx

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,48 @@ export default function ButtonLink({
4343

4444
// Track conversion if enabled
4545
if (trackConversion && siteConfig.analytics && typeof window.gtag === 'function') {
46+
// Don't intercept if event is already prevented, or if it's a modified/new-tab/download click
47+
if (event.defaultPrevented ||
48+
event.button !== 0 || // not left click
49+
event.metaKey || event.ctrlKey || event.altKey || event.shiftKey || // modifier keys
50+
event.currentTarget.target === '_blank' || // new tab
51+
event.currentTarget.hasAttribute('download')) { // download
52+
// Just track the event without preventing navigation
53+
try {
54+
const eventData: any = {
55+
action: 'get_started_click',
56+
category: 'Conversion',
57+
label: 'CTA Button',
58+
value: 1,
59+
};
60+
61+
// Only add acquisition_source if it exists (cold email visitors)
62+
const acquisitionSource = typeof window !== 'undefined'
63+
? sessionStorage.getItem('acquisition_source')
64+
: null;
65+
66+
if (acquisitionSource) {
67+
eventData.acquisition_source = acquisitionSource;
68+
}
69+
70+
// Add campaign person if it exists (LinkedIn connect campaigns)
71+
const campaignPerson = typeof window !== 'undefined'
72+
? sessionStorage.getItem('campaign_person')
73+
: null;
74+
75+
if (campaignPerson) {
76+
eventData.campaign_person = campaignPerson;
77+
}
78+
79+
gtag.event(eventData);
80+
} catch (error) {
81+
console.warn('Failed to track conversion event:', error);
82+
}
83+
return; // Let the browser handle navigation normally
84+
}
85+
86+
event.preventDefault(); // Only prevent for normal left clicks
87+
4688
try {
4789
const eventData: any = {
4890
action: 'get_started_click',
@@ -69,9 +111,27 @@ export default function ButtonLink({
69111
eventData.campaign_person = campaignPerson;
70112
}
71113

72-
gtag.event(eventData);
114+
// Use event_callback to ensure navigation happens after tracking
115+
window.gtag('event', eventData.action, {
116+
event_category: eventData.category,
117+
event_label: eventData.label,
118+
value: eventData.value,
119+
acquisition_source: eventData.acquisition_source,
120+
campaign_person: eventData.campaign_person,
121+
event_callback: () => {
122+
window.location.href = href || 'https://cloud.portaljs.com/';
123+
}
124+
});
125+
126+
// Fallback timeout in case gtag callback doesn't fire
127+
setTimeout(() => {
128+
window.location.href = href || 'https://cloud.portaljs.com/';
129+
}, 200);
130+
73131
} catch (error) {
74132
console.warn('Failed to track conversion event:', error);
133+
// Navigate anyway if tracking fails
134+
window.location.href = href || 'https://cloud.portaljs.com/';
75135
}
76136
}
77137
};

site/components/home/Hero.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,10 @@ export default function Hero() {
7474
<div className="py-10 dark:py-4">
7575
{' '}
7676
<H1 className="-ml-1 text-3xl sm:text-6xl xl:text-7xl bg-gradient-to-r from-blue-500 via-blue-400 to-blue-500 bg-clip-text text-transparent pb-3 font-semibold">
77-
Managed <br />
78-
Data Portal <br />
79-
In the Cloud
77+
The Data Portals Framework
8078
</H1>
8179
<H2 sub={true} className="mt-5 text-base sm:text-lg xl:text-xl">
82-
PortalJS Cloud is the simplest way to get started with open data.
83-
Designed for governments, nonprofits, and academic institutions,
84-
it lets you launch a modern, compliant portal in minutes.
80+
Create data portals people love to use - for internal data management and sharing, research data repositories, and open data portals.
8581
</H2>
8682
<div className="mt-5 mt-10 flex justify-center dark:xl:justify-start">
8783
<div className="mt-3 mt-0 flex gap-4">

site/components/home/KeyFeatures.tsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,54 @@ export const KeyFeatures = () => {
66
const { theme } = useTheme()
77
const features = [
88
{
9-
title: 'Launch in Minutes',
9+
title: 'Unified sites',
1010
description:
11-
'Get your data portal up and running in minutes, not months. No technical expertise required.',
12-
icon: `/static/icons/${theme}/clock.json`,
11+
'Present data and content in one seamless site, pulling datasets from a DMS (eg, CKAN or OpenMetadata) and content from a CMS (eg, WordPress or other).',
12+
icon: `/static/icons/${theme}/network.json`,
1313
style: 'dark:-rotate-[4deg]',
1414
},
1515
{
16-
title: 'Secure & Compliant',
16+
title: 'Developer friendly',
1717
description:
18-
'Built with security and compliance in mind. GDPR compliant and follows best practices.',
19-
icon: `/static/icons/${theme}/verified.json`,
18+
'Built with familiar frontend tech (Next.js and Tailwind CSS) with great local dev tooling.',
19+
icon: `/static/icons/${theme}/html.json`,
2020
style: 'dark:-rotate-[3deg]',
2121
},
2222
{
23-
title: 'Data Management',
23+
title: 'Batteries included',
2424
description:
25-
'Easily upload, manage, and organize your data with our intuitive interface.',
26-
icon: `/static/icons/${theme}/data-catalog.json`,
25+
'Ready-made portal components out of the box: catalog search, dataset pages, previews (tables, charts, maps), blogs, and more.',
26+
icon: `/static/icons/${theme}/layers.json`,
2727
style: 'dark:-rotate-[2deg]',
2828
},
2929
{
30-
title: 'Powerful Search',
30+
title: 'Easy to theme & customize',
3131
description:
32-
'Help users find what they need with powerful search capabilities across all your datasets.',
33-
icon: `/static/icons/${theme}/search.json`,
32+
'Installable themes, standard CSS/React tooling, quick route creation, and support for custom branding.',
33+
icon: `/static/icons/${theme}/paint-roller.json`,
3434
style: 'dark:-rotate-[4deg]',
3535
},
36+
{
37+
title: 'Extensible',
38+
description:
39+
'Extend with your own components, or import from the wider ecosystem.',
40+
icon: `/static/icons/${theme}/expand.json`,
41+
style: 'dark:-rotate-[3deg]',
42+
},
43+
{
44+
title: 'Enterprise ready',
45+
description:
46+
'Optional modules for authentication/SSO, role-based access control, data quality, and API management.',
47+
icon: `/static/icons/${theme}/padlock.json`,
48+
style: 'dark:-rotate-[2deg]',
49+
},
3650
]
3751

3852
return (
3953
<div className="py-24">
4054
<div className="">
41-
<H2 className="text-center">Key Features</H2>
42-
<div className="mt-16 grid grid-cols-1 gap-y-12 sm:grid-cols-2 sm:gap-x-12 lg:grid-cols-4 lg:gap-x-6">
55+
<H2 className="text-center">Features</H2>
56+
<div className="mt-16 grid grid-cols-1 gap-y-12 sm:grid-cols-2 sm:gap-x-12 lg:grid-cols-3 lg:gap-x-6">
4357
{features.map((feature) => (
4458
<div
4559
key={feature.title}

site/components/home/LaunchPortal.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CheckIcon } from '@heroicons/react/24/solid'
22
import { H2, H3 } from '../custom/header'
3+
import ButtonLink from '../ButtonLink'
34

45
export default function LaunchPortal() {
56
return (
@@ -8,14 +9,24 @@ export default function LaunchPortal() {
89
<div className="flex flex-col lg:flex-row gap-32 lg:justify-between">
910
<div className="!z-40">
1011
<H2 className=" mb-2 leading-[3rem]">
11-
Imagine Launching Your Data Portal in Minutes
12+
Launch your data portal in minutes
1213
</H2>
1314
<H3 className=" mb-4 max-w-2xl">
1415
Meet <b>PortalJS Cloud</b><b>the only solution on the market</b>{' '}
15-
that combines full public-sector compliance, CKAN compatibility,
16+
that combines full public-sector compliance, metadata backend compatibility,
1617
AI-powered features, and instant deployment — all in a fully
1718
managed package.
1819
</H3>
20+
<div className="mt-6">
21+
<ButtonLink
22+
href="https://cloud.portaljs.com/auth/signup"
23+
title="Deploy your data portal with PortalJS Cloud"
24+
className="text-sm"
25+
trackConversion={true}
26+
>
27+
Deploy your data portal
28+
</ButtonLink>
29+
</div>
1930
{/* <ul className="list-none list-inside mb-4 flex flex-col gap-1">
2031
<li className="">
2132
<div className="flex items-center gap-2">

0 commit comments

Comments
 (0)