Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

signoz vs datadog page revamp #1064

Merged
merged 32 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5019f02
Taken the base layout from unified observability and modified it a bit
yuvraajsj18 Dec 30, 2024
d6aab23
- Updated the introduction to highlight why engineering teams prefer …
yuvraajsj18 Dec 30, 2024
f353e93
adjusted font size hiararchy to be consistent
yuvraajsj18 Dec 30, 2024
fc7923d
Added images
yuvraajsj18 Dec 30, 2024
bcfa1ef
done till APM
yuvraajsj18 Dec 30, 2024
962f913
done till product comparison, added template for value section
yuvraajsj18 Dec 30, 2024
dabd678
Done till value section
yuvraajsj18 Dec 30, 2024
0c62cec
Added FAQ and modified FAQ accordian component to be left aligned
yuvraajsj18 Dec 30, 2024
a4b25d1
Base done
yuvraajsj18 Dec 30, 2024
f6dab1f
build
yuvraajsj18 Dec 30, 2024
eea43d5
added floating card
yuvraajsj18 Dec 31, 2024
959a29a
added closing option
yuvraajsj18 Dec 31, 2024
3e69a70
Add better transition
yuvraajsj18 Dec 31, 2024
ab2fd59
added table of content
yuvraajsj18 Dec 31, 2024
1bd7307
hide the table of content pill over footer
yuvraajsj18 Dec 31, 2024
3118fa1
swapped toc with cta card
yuvraajsj18 Jan 2, 2025
5f764c5
removed from video
yuvraajsj18 Jan 2, 2025
855f41b
add shadow to video
yuvraajsj18 Jan 2, 2025
7edfd4e
increase heading size
yuvraajsj18 Jan 2, 2025
1d54f1f
add exception feature page link
yuvraajsj18 Jan 2, 2025
2f7336c
created a key call out component
yuvraajsj18 Jan 2, 2025
cfa238e
build
yuvraajsj18 Jan 2, 2025
09f1042
save g from getting cut
yuvraajsj18 Jan 2, 2025
62d8def
opened links in new tab
yuvraajsj18 Jan 2, 2025
5c96732
remove new tab from migration form link
yuvraajsj18 Jan 2, 2025
43394d1
modified meta data
yuvraajsj18 Jan 2, 2025
9f19c26
mobile responsive
yuvraajsj18 Jan 2, 2025
dbc5dbc
heading links
yuvraajsj18 Jan 2, 2025
0222ffb
make links heading with icon
yuvraajsj18 Jan 2, 2025
1e9cd4b
toc links update url
yuvraajsj18 Jan 2, 2025
829c642
h3 to h4
yuvraajsj18 Jan 2, 2025
80ceb8f
build
yuvraajsj18 Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,373 changes: 2,373 additions & 0 deletions app/product-comparison/signoz-vs-datadog/SigNozVsDatadogV2.tsx

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions app/product-comparison/signoz-vs-datadog/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import SigNozVSDatadog from './SigNozVsDataDog'
import SigNozVsDatadogV2 from './SigNozVsDatadogV2'

import { Metadata } from 'next'

export const metadata: Metadata = {
title: 'SigNoz VS DataDog',
title: 'In Depth - SigNoz vs Datadog',
description:
'How is SigNoz a great alternative to Datadog? Learn where SigNoz is a better fit for your use cases when compared to Datadog.',
}

export default function SigNozVSDatadogPage() {
return <SigNozVSDatadog />
}
return <SigNozVsDatadogV2 />
}
33 changes: 15 additions & 18 deletions components/FAQAccordion/FAQAccordion.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
'use client'

import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronDown } from 'lucide-react';
import React, { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { ChevronDown } from 'lucide-react'

const FAQItem = ({ question, answer }) => {
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(false)

return (
<div className="border-b border-gray-200 my-4 last:border-b-0">
<div className="my-4 border-b border-gray-200 last:border-b-0">
<button
className="flex justify-between items-center w-full py-4 text-left"
className="flex w-full items-center justify-between py-4 text-left"
onClick={() => setIsOpen(!isOpen)}
>
<span className="font-medium text-base sm:text-lg">{question}</span>
<motion.div
animate={{ rotate: isOpen ? 180 : 0 }}
transition={{ duration: 0.3 }}
>
<ChevronDown className="w-4 h-4 sm:w-5 sm:h-5" />
<span className="text-base font-medium sm:text-lg">{question}</span>
<motion.div animate={{ rotate: isOpen ? 180 : 0 }} transition={{ duration: 0.3 }}>
<ChevronDown className="h-4 w-4 sm:h-5 sm:w-5" />
</motion.div>
</button>
<AnimatePresence>
Expand All @@ -36,17 +33,17 @@ const FAQItem = ({ question, answer }) => {
)}
</AnimatePresence>
</div>
);
};
)
}

const FAQAccordion = ({ faqs }) => {
return (
<div className="w-full max-w-lg mx-auto px-4 sm:px-6 lg:px-8">
<div className="w-full">
{faqs.map((faq, index) => (
<FAQItem key={index} question={faq.question} answer={faq.answer} />
))}
</div>
);
};
)
}

export default FAQAccordion;
export default FAQAccordion
19 changes: 19 additions & 0 deletions components/KeyPointCallout/KeyPointCallout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client'

import React from 'react'

interface KeyPointCalloutProps {
title?: string
children: React.ReactNode
}

const KeyPointCallout: React.FC<KeyPointCalloutProps> = ({ title, children }) => {
return (
<div className="float-right clear-right mb-8 ml-8 w-[300px] rounded-lg border-2 border-orange-500/30 bg-orange-500/10 p-6 shadow-lg shadow-orange-500/20 backdrop-blur-sm transition-all duration-300 hover:border-orange-500/40 hover:bg-orange-500/15 hover:shadow-xl hover:shadow-orange-500/30">
{title && <h4 className="mb-3 text-xl font-bold text-orange-400">{title}</h4>}
<div className="text-lg font-semibold leading-relaxed text-gray-200">{children}</div>
</div>
)
}

export default KeyPointCallout
87 changes: 87 additions & 0 deletions components/MigrationFloatingCard/MigrationFloatingCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client'

import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import { ArrowRight, X } from 'lucide-react'
import Button from '@/components/Button/Button'

const MigrationFloatingCard: React.FC = () => {
const [isVisible, setIsVisible] = useState(false)
const [isClosed, setIsClosed] = useState(false)

useEffect(() => {
const cardClosed = localStorage.getItem('migrationCardClosed')
if (cardClosed) {
setIsClosed(true)
}
}, [])

useEffect(() => {
const handleScroll = () => {
const scrollPosition = window.scrollY
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight

// Show when past 20% of page
const showThreshold = documentHeight * 0.2

// Hide when near the bottom section (adjust 800px based on your needs)
const hideThreshold = documentHeight - windowHeight - 800

if (scrollPosition > showThreshold && scrollPosition < hideThreshold) {
setIsVisible(true)
} else {
setIsVisible(false)
}
}

window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])

const handleClose = () => {
setIsClosed(true)
localStorage.setItem('migrationCardClosed', 'true')
}

return (
<div
className={`fixed bottom-6 right-6 z-50 hidden w-64 transform rounded-lg bg-gradient-to-r from-blue-900/90 to-purple-900/90 p-4 shadow-lg backdrop-blur-sm transition-all duration-500 ease-in-out hover:-translate-y-1 hover:shadow-xl lg:block ${
isVisible && !isClosed
? 'translate-y-0 opacity-100'
: 'pointer-events-none translate-y-8 opacity-0'
}`}
>
<button
onClick={handleClose}
className="absolute right-2 top-2 text-gray-400 hover:text-white"
aria-label="Close"
>
<X size={14} />
</button>

<h3 className="mb-2 text-lg font-bold text-white">Save up to 80% on your Datadog bill</h3>
<p className="mb-3 text-xs text-gray-300">
We provide migration support if your monthly Datadog bill is over $2000. Get started with
SigNoz quickly.
</p>
<div className="flex flex-col gap-2">
<Link href="/teams/" className="w-full">
<Button className="flex w-full items-center justify-center gap-1 text-xs font-bold">
Try SigNoz - Free <ArrowRight className="h-3 w-3" />
</Button>
</Link>
<Link href="https://signoz.io/product-comparison/migrate-from-datadog/" className="w-full">
<Button
type={Button.TYPES.SECONDARY}
className="flex w-full items-center justify-center gap-1 text-xs font-bold"
>
Request Migration Support <ArrowRight className="h-3 w-3" />
</Button>
</Link>
</div>
</div>
)
}

export default MigrationFloatingCard
181 changes: 181 additions & 0 deletions components/TableOfContents/FloatingTableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
'use client'

import React, { useState, useEffect } from 'react'
import { Menu, ChevronRight } from 'lucide-react'

interface TOCItem {
id: string
text: string
level: number
children?: TOCItem[]
}

const FloatingTableOfContents: React.FC = () => {
const [isOpen, setIsOpen] = useState(false)
const [tocItems, setTocItems] = useState<TOCItem[]>([])
const [isVisible, setIsVisible] = useState(true)

useEffect(() => {
const handleScroll = () => {
const scrollPosition = window.scrollY
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight

// Hide when near the bottom section (adjust 800px based on your needs)
const hideThreshold = documentHeight - windowHeight - 800

if (scrollPosition < hideThreshold) {
setIsVisible(true)
} else {
setIsVisible(false)
setIsOpen(false) // Also close the menu if it's open
}
}

window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])

useEffect(() => {
// Function to get text content without nested elements
const getTextContent = (element: Element): string => {
// Find the Link element inside the heading
const linkElement = element.querySelector('a')
if (linkElement) {
// Get all text nodes within the link, excluding the LinkIcon
return Array.from(linkElement.childNodes)
.filter((node) => node.nodeType === Node.TEXT_NODE)
.map((node) => node.textContent)
.join('')
.trim()
}
// Fallback to original behavior
return Array.from(element.childNodes)
.filter((node) => node.nodeType === Node.TEXT_NODE)
.map((node) => node.textContent)
.join('')
.trim()
}

// Function to build TOC structure
const buildTOC = () => {
const headings = document.querySelectorAll('h2, h3')
const items: TOCItem[] = []
let currentH2: TOCItem | null = null

headings.forEach((heading) => {
const text = getTextContent(heading)
// Restore the ID generation logic while keeping existing IDs
const id = heading.id || text.toLowerCase().replace(/\s+/g, '-') || ''
if (!heading.id) {
heading.id = id
}

const item: TOCItem = {
id,
text,
level: parseInt(heading.tagName[1]),
}

if (item.level === 2) {
currentH2 = item
items.push(item)
} else if (item.level === 3 && currentH2) {
if (!currentH2.children) {
currentH2.children = []
}
currentH2.children.push(item)
}
})

setTocItems(items)
}

// Initial build
buildTOC()

// Re-run buildTOC when the DOM changes
const observer = new MutationObserver(buildTOC)
observer.observe(document.body, {
childList: true,
subtree: true,
})

return () => observer.disconnect()
}, [])

const handleItemClick = (id: string) => {
const element = document.getElementById(id)
if (element) {
// Update URL without causing a page reload
window.history.pushState({}, '', `#${id}`)

element.scrollIntoView({ behavior: 'smooth' })
setIsOpen(false)
}
}

return (
<div
className={`fixed bottom-8 left-8 z-50 transition-all duration-300 ${
isVisible ? 'translate-y-0 opacity-100' : 'pointer-events-none translate-y-8 opacity-0'
}`}
>
{/* Menu Items */}
<div
className={`absolute bottom-16 left-0 min-w-[240px] rounded-lg bg-gray-800/95 p-3 shadow-xl backdrop-blur-sm transition-all duration-300 ${
isOpen
? 'pointer-events-auto translate-y-0 opacity-100'
: 'pointer-events-none translate-y-4 opacity-0'
}`}
>
<div className="flex max-h-[60vh] flex-col gap-1 overflow-y-auto">
{tocItems.map((item, index) => (
<div
key={item.id}
style={{
transition: `all 300ms cubic-bezier(0.4, 0, 0.2, 1) ${index * 50}ms`,
opacity: isOpen ? 1 : 0,
transform: `translateY(${isOpen ? 0 : 8}px)`,
}}
>
<button
onClick={() => handleItemClick(item.id)}
className="w-full rounded-md px-3 py-2 text-left text-sm text-white transition-colors hover:bg-gray-700/80"
>
{item.text}
</button>
{item.children && item.children.length > 0 && (
<div className="ml-3 flex flex-col gap-0.5 pt-0.5">
{item.children.map((child) => (
<button
key={child.id}
onClick={() => handleItemClick(child.id)}
className="flex items-center gap-1 rounded-md px-3 py-1.5 text-left text-xs text-gray-300 transition-colors hover:bg-gray-700/80"
>
<ChevronRight className="h-3 w-3" />
{child.text}
</button>
))}
</div>
)}
</div>
))}
</div>
</div>

{/* Toggle Button */}
<button
onClick={() => setIsOpen(!isOpen)}
className={`flex items-center gap-2 rounded-full bg-gray-800/90 px-4 py-2 text-white shadow-lg backdrop-blur-sm transition-all duration-300 hover:bg-gray-700/90 ${
isOpen ? 'bg-gray-700/90' : ''
}`}
>
<Menu className="h-4 w-4" />
<span className="text-xs font-medium">Table of Contents</span>
</button>
</div>
)
}

export default FloatingTableOfContents
Loading