diff --git a/components/Competitors/ComparisonTable.tsx b/components/Competitors/ComparisonTable.tsx new file mode 100644 index 00000000..fcee0ae9 --- /dev/null +++ b/components/Competitors/ComparisonTable.tsx @@ -0,0 +1,84 @@ +import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid' +import Image from 'next/image' +import { HiCheckCircle, HiDotsCircleHorizontal, HiXCircle } from 'react-icons/hi' +import highlightlogosmall from '../../public/images/logo-on-dark.png' +import logrocketlogofull from '../../public/images/logrocketlogofull.png' +import logrocketlogosmall from '../../public/images/logrocketlogosmall.png' +import { HighlightLogo } from '../common/HighlightLogo/HighlightLogo' +import { Typography } from '../common/Typography/Typography' +import { ComparisonTableRow, ComparisonTableSection, Competitor } from './competitors' + +export default function ComparisonTable(props: { competitor: Competitor }) { + if (!props.competitor) { + return
No Competitor Loaded
+ } + + return ( +
+ {props.competitor.sections.map((section: ComparisonTableSection, i) => ( +
+
+ + {section.title} + +
+
+
+ +
+ LogRocket Logo +
+
+ LogRocket Logo + LogRocket Logo +
+
+
+ {section.rows.map((row: ComparisonTableRow, j) => ( +
+ + {row.feature} + +
+ + +
+ {row.highlight == 1 ? ( + + ) : ( +
+ + + {row.highlight == 0.5 && ( +
+ + Coming soon + +
+ )} +
+ )} +
+
+ {row.competitor ? ( + + ) : ( + + )} +
+
+
+ ))} +
+ ))} +
+ ) +} diff --git a/components/Competitors/competitors.ts b/components/Competitors/competitors.ts new file mode 100644 index 00000000..33eb82b7 --- /dev/null +++ b/components/Competitors/competitors.ts @@ -0,0 +1,120 @@ +import { StaticImageData } from 'next/image' + +export type ComparisonTableRow = { + feature: string + highlight: 0 | 0.5 | 1 + competitor: 0 | 1 + tooltip?: string +} + +export type ComparisonTableSection = { + title: string + rows: ComparisonTableRow[] +} + +export type Competitor = { + slug: string + name: string + header: string + subheader: string + subHeader2: string + logo?: StaticImageData + sections: ComparisonTableSection[] +} + +export const COMPETITORS: { [k: string]: Competitor } = { + 'log-rocket': { + slug: 'log-rocket', + name: 'LogRocket', + header: 'The Open Source Logrocket Alternative.', + subheader: 'Pixel-perfect video replay of your web application. Step into the shoes of your users.', + subHeader2: 'An Open Source, Fullstack Alternative to Logrocket. Get Started for free in minutes.', + sections: [ + { + title: 'General', + rows: [ + { + feature: 'Unlimited Team Members', + highlight: 1, + competitor: 1, + }, + { + feature: 'Unlimited Team Members', + highlight: 1, + competitor: 0, + }, + { + feature: 'Unlimited Team Members', + highlight: 1, + competitor: 1, + }, + { + feature: 'Unlimited Team Members', + highlight: 0.5, + competitor: 1, + }, + { + feature: 'Unlimited Team Members', + highlight: 1, + competitor: 1, + }, + ], + }, + { + title: 'Session Replay', + rows: [ + { + feature: 'Commenting / Mentions', + highlight: 1, + competitor: 1, + }, + { + feature: 'Heatmaps', + highlight: 1, + competitor: 0, + }, + { + feature: 'Session Sharing', + highlight: 1, + competitor: 1, + }, + { + feature: 'Privacy SDKs', + highlight: 0.5, + competitor: 0, + }, + { + feature: 'Embedded Error Monitoring', + highlight: 1, + competitor: 1, + }, + { + feature: 'Canvas & WebGL Recording', + highlight: 1, + competitor: 1, + }, + { + feature: 'Session-level Debugging Data', + highlight: 1, + competitor: 1, + }, + ], + }, + { + title: 'Error Monitoring', + rows: [ + { + feature: 'Embedded Session Replay', + highlight: 1, + competitor: 1, + }, + { + feature: 'Support for Backend SDKs', + highlight: 1, + competitor: 0, + }, + ], + }, + ], + }, +} diff --git a/pages/session-replay/[slug].tsx b/pages/session-replay/[slug].tsx new file mode 100644 index 00000000..7093b607 --- /dev/null +++ b/pages/session-replay/[slug].tsx @@ -0,0 +1,162 @@ +import classNames from 'classnames' +import { GetStaticPaths, GetStaticProps } from 'next' +import Image from 'next/image' +import Link from 'next/link' +import { useState } from 'react' +import { MdKeyboardReturn } from 'react-icons/md' +import { PrimaryButton } from '../../components/common/Buttons/PrimaryButton' +import { FooterCallToAction } from '../../components/common/CallToAction/FooterCallToAction' +import { OSSCallToAction } from '../../components/common/CallToAction/OSSCallToAction' +import Footer from '../../components/common/Footer/Footer' +import Navbar from '../../components/common/Navbar/Navbar' +import { Section } from '../../components/common/Section/Section' +import { Typography } from '../../components/common/Typography/Typography' +import CompetitorTable from '../../components/Competitors/ComparisonTable' +import { Competitor, COMPETITORS } from '../../components/Competitors/competitors' +import { CompaniesReel } from '../../components/Home/CompaniesReel/CompaniesReel' +import { CustomerReviewTrack } from '../../components/Home/CustomerReviewTrack' +import homeStyles from '../../components/Home/Home.module.scss' +import errorMonitoringHero from '../../public/images/features/errorMonitoringHero.png' +import loggingHero from '../../public/images/features/loggingHero.png' +import sessionReplayHero from '../../public/images/features/sessionReplayHero.png' +import sessionscreenshot from '../../public/images/sessionscreenshot.png' + +import { AnimateFeatureHeroRight, AnimateFeatureHeroXL } from '../../components/Animate' + +const CompetitorComparisonPage = ({ competitor }: { competitor: Competitor }) => { + const [imageLoaded, setImageLoaded] = useState(false) + + return ( +
+ Hero Background + Hero Background + Hero Background + +
+ + +
+ Explore highlight.io +
+
+ +
+
+
+
+
+

The Open Source {competitor.name} alternative.

+ + + {competitor.subheader} + +
+ + + Get started for free + + + + + Read our docs + + +
+
+
+
+ + Feature Spotlight setImageLoaded(true)} + /> + + + Feature Spotlight setImageLoaded(true)} + /> + + Feature Spotlight setImageLoaded(true)} + /> +
+
+
+
+
+

+ How does highlight.io stack up? +

+
+ + {competitor.subHeader2} + +
+
+ +
+
+ + +
+ +
+
+
+
+ + Don't take our word. Read our customer review section → + +
+
+
+ + +
+
+ ) +} + +export const getStaticPaths: GetStaticPaths = async () => { + return { + paths: Object.keys(COMPETITORS).map((k: string) => ({ + params: { slug: k }, + })), + fallback: 'blocking', + } +} + +//Gets list of products from products.ts +export const getStaticProps: GetStaticProps = async ({ params }) => { + const slug = params?.slug as string + + // Handle event slugs which don't exist + if (!COMPETITORS[slug]) { + return { + notFound: true, + } + } + + return { + props: { + competitor: COMPETITORS[slug], + }, + } +} + +export default CompetitorComparisonPage diff --git a/public/images/logrocketlogofull.png b/public/images/logrocketlogofull.png new file mode 100644 index 00000000..c883bd22 Binary files /dev/null and b/public/images/logrocketlogofull.png differ diff --git a/public/images/logrocketlogosmall.png b/public/images/logrocketlogosmall.png new file mode 100644 index 00000000..64e80a70 Binary files /dev/null and b/public/images/logrocketlogosmall.png differ