website-monitor/frontend/components/landing/PolicyDemoVisual.tsx

165 lines
6.2 KiB
TypeScript

'use client'
import { motion } from 'framer-motion'
import { useState, useEffect } from 'react'
import { FileCheck, Check } from 'lucide-react'
function resolveHsl(cssVar: string): string {
if (typeof window === 'undefined') return 'transparent'
const value = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim()
return value ? `hsl(${value})` : 'transparent'
}
export function PolicyDemoVisual() {
const [phase, setPhase] = useState(0)
const [colors, setColors] = useState({ burgundy: '#993350', teal: '#2e6b6a', border: '#27272a', mutedFg: '#aba49d' })
useEffect(() => {
setColors({
burgundy: resolveHsl('--burgundy'),
teal: resolveHsl('--teal'),
border: resolveHsl('--border'),
mutedFg: resolveHsl('--muted-foreground'),
})
}, [])
useEffect(() => {
const interval = setInterval(() => {
setPhase(p => (p + 1) % 2)
}, 3000)
return () => clearInterval(interval)
}, [])
return (
<div className="relative h-full bg-gradient-to-br from-background via-background to-[hsl(var(--burgundy))]/5 rounded-xl p-4 overflow-hidden">
{/* Document Header */}
<div className="mb-3 flex items-center justify-between">
<div className="flex items-center gap-2">
<FileCheck className="h-4 w-4 text-[hsl(var(--burgundy))]" />
<span className="text-xs font-bold text-foreground">Terms of Service</span>
</div>
<motion.div
className="px-2 py-0.5 rounded-full border text-[9px] font-bold"
animate={{
borderColor: phase === 1 ? colors.teal : colors.border,
backgroundColor: phase === 1 ? `${colors.teal}1a` : 'rgba(0,0,0,0)',
color: phase === 1 ? colors.teal : colors.mutedFg
}}
transition={{ duration: 0.5 }}
>
{phase === 0 ? 'v2.1' : 'v2.2'}
</motion.div>
</div>
{/* Document Content */}
<motion.div
className="space-y-2 p-3 rounded-lg border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 overflow-hidden"
animate={{
borderColor: phase === 1 ? colors.burgundy : colors.border,
boxShadow: phase === 1
? `0 0 20px ${colors.burgundy}33`
: '0 1px 3px rgba(0,0,0,0.2)'
}}
transition={{ duration: 0.5 }}
>
{/* Section 4.2 */}
<div className="space-y-1.5">
<div className="text-[10px] font-bold text-zinc-300">
Section 4.2 - Data Retention
</div>
{/* Text Lines */}
<div className="space-y-1 text-[9px] text-zinc-500 leading-relaxed">
<p>We will retain your personal data for</p>
{/* Changing text */}
<motion.div
className="relative rounded"
layout
>
<motion.p
animate={{
backgroundColor: phase === 1 ? `${colors.burgundy}1a` : 'rgba(0,0,0,0)',
paddingLeft: phase === 1 ? '4px' : '0px',
paddingRight: phase === 1 ? '4px' : '0px',
color: phase === 1 ? colors.burgundy : 'inherit',
fontWeight: phase === 1 ? 600 : 400
}}
transition={{ duration: 0.4 }}
className="relative inline-block rounded"
>
{phase === 0 ? (
'as long as necessary to fulfill purposes'
) : (
<motion.span
initial={{ opacity: 0, y: -5 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
a minimum of 90 days after account deletion
</motion.span>
)}
</motion.p>
{/* Change highlight indicator */}
{phase === 1 && (
<motion.div
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ duration: 0.4 }}
className="absolute -left-1 top-0 bottom-0 w-0.5 bg-[hsl(var(--burgundy))] rounded-full origin-left"
/>
)}
</motion.div>
<p>outlined in our Privacy Policy.</p>
</div>
</div>
{/* Diff Stats */}
{phase === 1 && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{ delay: 0.3 }}
className="pt-2 border-t border-zinc-800 flex items-center justify-between"
>
<div className="flex items-center gap-3 text-[8px] text-zinc-500">
<span className="flex items-center gap-1">
<span className="w-2 h-2 rounded bg-green-500/20 border border-green-500" />
+18 words
</span>
<span className="flex items-center gap-1">
<span className="w-2 h-2 rounded bg-[hsl(var(--burgundy))]/20 border border-[hsl(var(--burgundy))]" />
-7 words
</span>
</div>
</motion.div>
)}
</motion.div>
{/* Audit Trail Badge */}
{phase === 1 && (
<motion.div
initial={{ opacity: 0, y: 5, scale: 0.9 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ delay: 0.5 }}
className="mt-3 flex items-center gap-2 p-2 rounded-lg bg-[hsl(var(--burgundy))]/10 border border-[hsl(var(--burgundy))]/30"
>
<div className="flex-shrink-0 flex items-center justify-center w-5 h-5 rounded-full bg-[hsl(var(--burgundy))] text-white">
<Check className="h-3 w-3" strokeWidth={3} />
</div>
<div className="flex-1">
<div className="text-[9px] font-bold text-[hsl(var(--burgundy))]">
Audit trail saved
</div>
<div className="text-[8px] text-[hsl(var(--burgundy))]/80">
Snapshot archived for compliance
</div>
</div>
</motion.div>
)}
</div>
)
}