diff --git a/apps/public/src/app/(content)/features/_components/feature-card.tsx b/apps/public/src/app/(content)/features/_components/feature-card.tsx index b9378a9c..c5d59219 100644 --- a/apps/public/src/app/(content)/features/_components/feature-card.tsx +++ b/apps/public/src/app/(content)/features/_components/feature-card.tsx @@ -1,31 +1,34 @@ -import { FeatureCardContainer } from '@/components/feature-card'; -import { ArrowRightIcon } from 'lucide-react'; +import { ArrowRightIcon, type LucideIcon } from 'lucide-react'; import Link from 'next/link'; +import { FeatureCardContainer } from '@/components/feature-card'; interface FeatureCardLinkProps { url: string; title: string; description: string; + icon?: LucideIcon; } export function FeatureCardLink({ url, title, description, + icon: Icon, }: FeatureCardLinkProps) { return ( -
-
-

+
+
+ {Icon && } +

{title}

-

+

{description}

- +
diff --git a/apps/public/src/app/(content)/features/page.tsx b/apps/public/src/app/(content)/features/page.tsx index 3aacf597..d0de9271 100644 --- a/apps/public/src/app/(content)/features/page.tsx +++ b/apps/public/src/app/(content)/features/page.tsx @@ -1,3 +1,20 @@ +import type { LucideIcon } from 'lucide-react'; +import { + BellIcon, + ConeIcon, + DollarSignIcon, + FilterIcon, + GlobeIcon, + MonitorIcon, + MousePointerClickIcon, + PieChartIcon, + RefreshCwIcon, + ShareIcon, + UserIcon, + WorkflowIcon, +} from 'lucide-react'; +import type { Metadata } from 'next'; +import { FeatureCardLink } from './_components/feature-card'; import { FeatureHero } from '@/app/(content)/features/[slug]/_components/feature-hero'; import { CtaBanner } from '@/app/(home)/_sections/cta-banner'; import { Section, SectionHeader } from '@/components/section'; @@ -5,8 +22,21 @@ import { WindowImage } from '@/components/window-image'; import { url } from '@/lib/layout.shared'; import { getOgImageUrl, getPageMetadata } from '@/lib/metadata'; import { featureSource } from '@/lib/source'; -import type { Metadata } from 'next'; -import { FeatureCardLink } from './_components/feature-card'; + +const featureIcons: Record = { + conversion: FilterIcon, + 'data-visualization': PieChartIcon, + 'event-tracking': MousePointerClickIcon, + funnels: ConeIcon, + 'identify-users': UserIcon, + integrations: WorkflowIcon, + notifications: BellIcon, + retention: RefreshCwIcon, + 'revenue-tracking': DollarSignIcon, + 'session-tracking': MonitorIcon, + 'share-and-collaborate': ShareIcon, + 'web-analytics': GlobeIcon, +}; export const metadata: Metadata = getPageMetadata({ title: 'Product analytics features', @@ -32,36 +62,37 @@ export default async function FeaturesIndexPage() {
-
+
{features.map((feature) => ( ))}

); diff --git a/apps/public/src/app/(content)/open-source-analytics/page.tsx b/apps/public/src/app/(content)/open-source-analytics/page.tsx new file mode 100644 index 00000000..8352c9da --- /dev/null +++ b/apps/public/src/app/(content)/open-source-analytics/page.tsx @@ -0,0 +1,574 @@ +import { + ArrowRightIcon, + BarChart3Icon, + CalendarIcon, + CookieIcon, + GithubIcon, + InfinityIcon, + LayersIcon, + LineChartIcon, + RefreshCwIcon, + RocketIcon, + ServerIcon, + ShieldCheckIcon, + UnlockIcon, + UserIcon, + UsersIcon, +} from 'lucide-react'; +import type { Metadata } from 'next'; +import Link from 'next/link'; +import Script from 'next/script'; +import { CtaBanner } from '@/app/(home)/_sections/cta-banner'; +import { HeroContainer } from '@/app/(home)/_sections/hero'; +import { FaqItem, Faqs } from '@/components/faq'; +import { FeatureCard } from '@/components/feature-card'; +import { GetStartedButton } from '@/components/get-started-button'; +import { DataOwnershipIllustration } from '@/components/illustrations/data-ownership'; +import { PrivacyIllustration } from '@/components/illustrations/privacy'; +import { ProductAnalyticsIllustration } from '@/components/illustrations/product-analytics'; +import { WebAnalyticsIllustration } from '@/components/illustrations/web-analytics'; +import { Perks } from '@/components/perks'; +import { Section, SectionHeader } from '@/components/section'; +import { Testimonial } from '@/components/testimonial'; +import { Button } from '@/components/ui/button'; +import { WindowImage } from '@/components/window-image'; +import { url } from '@/lib/layout.shared'; +import { getOgImageUrl, getPageMetadata } from '@/lib/metadata'; +import { cn } from '@/lib/utils'; + +export const metadata: Metadata = getPageMetadata({ + title: 'Open Source Analytics | Web & Product Analytics Platform', + description: + 'OpenPanel is an open source analytics platform for web and product teams. Privacy-first, cookieless, self-hostable. Combine web analytics and product analytics in one tool. Free trial.', + url: url('/open-source-analytics'), + image: getOgImageUrl('/open-source-analytics'), +}); + +const jsonLd = { + '@context': 'https://schema.org', + '@type': 'WebPage', + name: 'Open Source Analytics | Web & Product Analytics Platform | OpenPanel', + description: + 'OpenPanel is an open source analytics platform for web and product teams. Privacy-first, cookieless, self-hostable. Combine web analytics and product analytics in one tool.', + url: url('/open-source-analytics'), + publisher: { + '@type': 'Organization', + name: 'OpenPanel', + logo: { + '@type': 'ImageObject', + url: url('/logo.png'), + }, + }, + mainEntity: { + '@type': 'SoftwareApplication', + name: 'OpenPanel', + applicationCategory: 'AnalyticsApplication', + operatingSystem: 'Web', + url: url('/'), + offers: { + '@type': 'Offer', + price: '0', + priceCurrency: 'USD', + description: 'Free 30-day trial, self-host for free', + }, + }, +}; + +const heroPerks = [ + { text: 'Open source (AGPL-3.0)', icon: GithubIcon }, + { text: 'Self-hostable', icon: ServerIcon }, + { text: 'Cookieless tracking', icon: CookieIcon }, + { text: 'GDPR compliant', icon: ShieldCheckIcon }, + { text: 'Web + product analytics', icon: BarChart3Icon }, + { text: '30-day free trial', icon: CalendarIcon }, +]; + +export default function OpenSourceAnalyticsPage() { + return ( +
+