mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
The /analytics landing page hardcoded theme-independent colors (var(--pure-black), var(--pure-white), --neutral-*) into the hero ground, dashboard mock, code windows and section washes. In light mode that meant near-black ink on a pure-black hero and white chart lines on light surfaces — unreadable and harsh. Swap them for @hanzo/design's theme-aware tokens (--background, --muted, --secondary, --primary, --muted-foreground). Dark rendering is unchanged; light mode now resolves correctly. Verified with headless Chromium (hero bg/ink before vs after) and clean tsc --noEmit / design lint. Co-authored-by: Hanzo Dev <[email protected]>
175 lines
7.6 KiB
TypeScript
175 lines
7.6 KiB
TypeScript
'use client'
|
|
|
|
import React from "react";
|
|
import { motion } from "@/components/motion";
|
|
import { LineChart } from "lucide-react";
|
|
import { Title as Heading } from '@hanzo/ui/marketing'
|
|
import { Lattice, Sub, ink, tint } from '../kit'
|
|
import { Box, Text, XStack, YStack } from '@hanzo/ui'
|
|
import { phrase } from '@hanzo/i18n'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
|
|
/** Each insight's heading, and its line with the figure as an argument. */
|
|
const INSIGHTS = [
|
|
{ head: phrase('Traffic Anomaly'), line: phrase('Unusual spike detected at {time}'), values: { time: '14:32 UTC' } },
|
|
{ head: phrase('Conversion Opportunity'), line: phrase('Checkout abandonment {share} higher on mobile'), values: { share: '23%' } },
|
|
{ head: phrase('Performance Alert'), line: phrase('API latency increased by {delay}'), values: { delay: '150ms' } },
|
|
]
|
|
|
|
/** A pane of the demo: a hairline on the sunken ground. */
|
|
function Pane({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<Box rounded="var(--radius-lg)" borderWidth={1} borderColor="var(--neutral-800)" bg="$sunken" p={20}>
|
|
{children}
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
const AIAnalysisDemo = () => {
|
|
const { t } = useI18n()
|
|
return (
|
|
<motion.div initial={{ opacity: 0, y: 40 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.7 }}>
|
|
<Box
|
|
position="relative"
|
|
overflow="hidden"
|
|
p={24}
|
|
rounded={16}
|
|
borderWidth={1}
|
|
borderColor="var(--neutral-800)"
|
|
boxShadow="var(--shadow-xl)"
|
|
$platform-web={{ background: 'linear-gradient(to right, var(--muted), color-mix(in oklab, var(--muted) 50%, transparent))' }}
|
|
>
|
|
<Lattice size={24} opacity={0.02} />
|
|
|
|
<Box position="relative" z="var(--z-raised)">
|
|
<XStack items="center" mb="$5" gap="$3">
|
|
<LineChart size={24} color="var(--foreground)" />
|
|
<Heading render="h3" quiet>
|
|
{t('AI Analysis in Action')}
|
|
</Heading>
|
|
</XStack>
|
|
|
|
{/* One column on a phone, three from `$md` — the fixed three never
|
|
collapse and the wide chart runs off the side. */}
|
|
<Box display="grid" gridTemplateColumns="minmax(0,1fr)" gap="$5" $md={{ gridTemplateColumns: 'repeat(3, minmax(0,1fr))' }}>
|
|
<Box $md={{ gridColumn: 'span 2' }} minW={0}>
|
|
<Pane>
|
|
<Sub mb={16}>{t('Traffic Anomaly Detection')}</Sub>
|
|
<Box position="relative" height={240}>
|
|
{/* Base line chart */}
|
|
<svg width="100%" height="100%" viewBox="0 0 300 100" preserveAspectRatio="none">
|
|
<motion.path
|
|
d="M0,80 C25,70 50,65 75,60 C100,55 125,50 150,55 C175,60 200,80 225,50 C250,20 275,35 300,30"
|
|
fill="none"
|
|
stroke="var(--primary)"
|
|
strokeWidth="2"
|
|
initial={{ pathLength: 0 }}
|
|
whileInView={{ pathLength: 1 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 2 }}
|
|
/>
|
|
|
|
{/* Anomaly area */}
|
|
<motion.path
|
|
d="M200,80 C206,65 212,40 218,20 C224,30 230,45 236,50"
|
|
fill="none"
|
|
stroke="var(--muted-foreground)"
|
|
strokeWidth="3"
|
|
strokeDasharray="2,2"
|
|
initial={{ opacity: 0 }}
|
|
whileInView={{ opacity: 1 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.3, delay: 1.8 }}
|
|
/>
|
|
|
|
{/* Anomaly circle */}
|
|
<motion.circle
|
|
cx="218"
|
|
cy="20"
|
|
r="5"
|
|
fill="var(--muted-foreground)"
|
|
initial={{ opacity: 0, scale: 0 }}
|
|
whileInView={{ opacity: 1, scale: 1 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.3, delay: 2 }}
|
|
/>
|
|
</svg>
|
|
|
|
{/* Anomaly detection popup */}
|
|
<Box position="absolute" t={16} r={32}>
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -10 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.3, delay: 2.2 }}
|
|
>
|
|
<YStack rounded={4} borderWidth={1} borderColor="var(--border)" py={8} px={12} $platform-web={{ backgroundColor: tint(10) }}>
|
|
<Text display="block" mb={4} fontSize="$1" lineHeight="1.25rem" fontWeight="700" color="var(--foreground)">
|
|
{t('Anomaly Detected')}
|
|
</Text>
|
|
<Text display="block" fontSize="$1" lineHeight="1rem" color="var(--foreground)">
|
|
{t('Unusual traffic spike')}
|
|
</Text>
|
|
<Text display="block" fontSize="$1" lineHeight="1rem" color="var(--foreground)">
|
|
{t('Confidence: {n}', { n: '98.7%' })}
|
|
</Text>
|
|
</YStack>
|
|
</motion.div>
|
|
</Box>
|
|
</Box>
|
|
</Pane>
|
|
</Box>
|
|
|
|
<YStack gap="$4">
|
|
<Pane>
|
|
<Sub mb={12}>{t('AI Insights')}</Sub>
|
|
<motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ duration: 0.5, delay: 2.4 }}>
|
|
<YStack gap={12}>
|
|
{INSIGHTS.map(({ head, line, values }) => (
|
|
<Box key={head}>
|
|
<Text display="block" fontSize="$2" lineHeight="1.25rem" fontWeight="500" $platform-web={{ color: ink(70) }}>
|
|
{t(head)}
|
|
</Text>
|
|
<Text display="block" fontSize="$2" lineHeight="1.25rem" color="var(--muted-foreground)">
|
|
{t(line, values)}
|
|
</Text>
|
|
</Box>
|
|
))}
|
|
</YStack>
|
|
</motion.div>
|
|
</Pane>
|
|
|
|
<motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ duration: 0.5, delay: 2.6 }}>
|
|
<Box rounded={12} borderWidth={1} borderColor="var(--border)" p={20} $platform-web={{ backgroundColor: tint(10) }}>
|
|
<Sub mb={8}>{t('AI Recommendation')}</Sub>
|
|
<Text render="p" display="block" fontSize="$2" lineHeight="1.15rem" $platform-web={{ color: ink(80) }}>
|
|
{t('Based on the traffic pattern analysis, we recommend scaling your infrastructure in the US-West region for the next {n} hours.', { n: 3 })}
|
|
</Text>
|
|
<Text
|
|
render={<button type="button" />}
|
|
mt={12}
|
|
py={4}
|
|
px={12}
|
|
borderWidth={0}
|
|
rounded={4}
|
|
bg="var(--primary)"
|
|
fontSize="$2"
|
|
lineHeight="1.15rem"
|
|
color="var(--primary-foreground)"
|
|
cursor="pointer"
|
|
$platform-web={{ display: 'inline-block' }}
|
|
>
|
|
{t('Apply Recommendation')}
|
|
</Text>
|
|
</Box>
|
|
</motion.div>
|
|
</YStack>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
</motion.div>
|
|
);
|
|
};
|
|
|
|
export default AIAnalysisDemo;
|