import { useId, useRef, useState } from 'react' import Image from 'next/image' import clsx from 'clsx' import { motion, useInView, useMotionValue } from 'framer-motion' import { AppScreen } from '@/components/AppScreen' import { AppStoreLink } from '@/components/AppStoreLink' import { Button } from '@/components/Button' import { Container } from '@/components/Container' import { PhoneFrame } from '@/components/PhoneFrame' import berniePic from '@/images/profiles/bernie.png' import profile1 from '@/images/profiles/profile-1.png' import profile2 from '@/images/profiles/profile-2.png' import {ArrowPathRoundedSquareIcon, ArrowUturnLeftIcon, Bars3Icon} from '@heroicons/react/20/solid' import Link from 'next/link' function BackgroundIllustration(props) { let id = useId() return (
) } function PlayIcon(props) { return ( ) } const prices = [ 997.56, 944.34, 972.25, 832.4, 888.76, 834.8, 805.56, 767.38, 861.21, 669.6, 694.39, 721.32, 694.03, 610.1, 502.2, 549.56, 611.03, 583.4, 610.14, 660.6, 752.11, 721.19, 638.89, 661.7, 694.51, 580.3, 638.0, 613.3, 651.64, 560.51, 611.45, 670.68, 752.56, ] const maxPrice = Math.max(...prices) const minPrice = Math.min(...prices) function Chart({ className, activePointIndex, onChangeActivePointIndex, width: totalWidth, height: totalHeight, paddingX = 0, paddingY = 0, gridLines = 6, ...props }) { let width = totalWidth - paddingX * 2 let height = totalHeight - paddingY * 2 let id = useId() let svgRef = useRef() let pathRef = useRef() let isInView = useInView(svgRef, { amount: 0.5, once: true }) let pathWidth = useMotionValue(0) let [interactionEnabled, setInteractionEnabled] = useState(false) let path = '' let points = [] for (let index = 0; index < prices.length; index++) { let x = paddingX + (index / (prices.length - 1)) * width let y = paddingY + (1 - (prices[index] - minPrice) / (maxPrice - minPrice)) * height points.push({ x, y }) path += `${index === 0 ? 'M' : 'L'} ${x.toFixed(4)} ${y.toFixed(4)}` } return ( onChangeActivePointIndex(null), onPointerMove: (event) => { let x = event.nativeEvent.offsetX let closestPointIndex let closestDistance = Infinity for ( let pointIndex = 0; pointIndex < points.length; pointIndex++ ) { let point = points[pointIndex] let distance = Math.abs(point.x - x) if (distance < closestDistance) { closestDistance = distance closestPointIndex = pointIndex } else { break } } onChangeActivePointIndex(closestPointIndex) }, } : {})} {...props} > {[...Array(gridLines - 1).keys()].map((index) => ( ))} { pathWidth.set( pathRef.current.getPointAtLength( pathLength * pathRef.current.getTotalLength() ).x ) }} onAnimationComplete={() => setInteractionEnabled(true)} /> {activePointIndex !== null && ( <> )} ) } function Post({ username, text, profileImage }) { return (
{ username }

{ text }

) } function AppDemo() { return (
Akkoma
) } export function Hero() { return (

Be very cool on the internet

Communicate with all your friends on the fediverse, no matter if they're on mastodon, pleroma, or any other fediverse software.
Send them fancy markdown animations! React to their posts with custom emoji!

  • Source Code
  • Documentation
) }