Finished animations #12

Open
graphite wants to merge 8 commits from graphite/animations2 into main AGit
6 changed files with 78 additions and 64 deletions
Showing only changes of commit 91bd54a8a2 - Show all commits

View file

@ -0,0 +1,26 @@
'use client';
import { motion } from "framer-motion"
import { useState } from "react";
const LinkButton = ({text, href, onPress}: {text: string, href: string, onPress?: () => any}) => {
const [buttonHovered, setButtonHovered] = useState( false );
const [buttonPressed, setButtonPressed] = useState( false );
return (
<div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
<motion.a
href={href}
className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px' }}
animate={{opacity: buttonHovered ? 0.8 : 1}}
onMouseEnter={()=>setButtonHovered(true)}
onMouseLeave={()=>setButtonHovered(false)}
onClick={()=>{setButtonPressed(true); onPress && onPress();}}
>
{text}
</motion.a>
</div>
);
}
export default LinkButton;

View file

@ -2,6 +2,7 @@
import { Transition } from "@headlessui/react"; import { Transition } from "@headlessui/react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { useState } from "react"; import { useState } from "react";
import LinkButton from "./link-button";
const Logo = () => { const Logo = () => {
@ -26,7 +27,7 @@ const Logo = () => {
</motion.a> </motion.a>
{/* </Transition> */} {/* </Transition> */}
<div style={{ marginBottom: '40px', marginRight: '40px' }}></div> <div style={{ marginBottom: '40px', marginRight: '40px' }}></div>
<motion.a {/* <motion.a
href="/about-us" href="/about-us"
className="rounded-md bg-white text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white" className="rounded-md bg-white text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px', marginRight: '40px', padding: '10px' }} style={{ marginBottom: '40px', marginRight: '40px', padding: '10px' }}
@ -35,7 +36,8 @@ const Logo = () => {
onMouseLeave={()=>setAboutButtonHovered(false)} onMouseLeave={()=>setAboutButtonHovered(false)}
> >
About us About us
</motion.a> </motion.a> */}
<LinkButton text="About us" href="/about-us"/>
</div> </div>
) )
} }

View file

@ -1,8 +1,10 @@
import { ReactComponentElement, ReactNode } from "react"; import { ReactComponentElement, ReactNode, useEffect } from "react";
import { AnswerType, Question } from "../lib/question"; import { AnswerType, Question } from "../lib/question";
import { SessionState } from "../lib/session"; import { SessionState } from "../lib/session";
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/outline"; import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/outline";
import { Button, Transition } from "@headlessui/react"; import { Button, Transition } from "@headlessui/react";
import wait from "../lib/delay";
import { motion } from "framer-motion";
const QuestionView = ({ question, setState, state }: { question: Question, setState: any, state: SessionState }) => { const QuestionView = ({ question, setState, state }: { question: Question, setState: any, state: SessionState }) => {
@ -16,6 +18,10 @@ const QuestionView = ({ question, setState, state }: { question: Question, setSt
})) }))
} }
useEffect( () => {
wait( 1000 );
}, [] );
const handleAnswerClick = (right: boolean) => { const handleAnswerClick = (right: boolean) => {
setState( (prevState: SessionState) => ({ setState( (prevState: SessionState) => ({
...prevState, ...prevState,
@ -47,14 +53,16 @@ const QuestionView = ({ question, setState, state }: { question: Question, setSt
{question.text} {question.text}
</h1> </h1>
</Transition> </Transition>
<Transition {/* <Transition
show={(question && state.opened[ question.id ]) ? true : false} show={(question && state.opened[ question.id ]) ? true : false}
enter="transition-opacity duration-300" enter="transition-opacity duration-300"
enterFrom="opacity-0" enterFrom="opacity-0"
enterTo="opacity-90" enterTo="opacity-90"
leave="transition-opacity duration-150" leave="transition-opacity duration-150"
leaveFrom="opacity-90" leaveFrom="opacity-90"
leaveTo="opacity-0"> leaveTo="opacity-0"> */}
{/* <motion.div animate={{visibility: ((question && state.opened[ question.id ]) ? "visible" : "collapse") }}> */}
<motion.div animate={(question && state.opened[ question.id ]) ? {visibility: "visible", opacity: 1} : {visibility: "collapse", opacity: 0}}>
<div><p className="mt-6 text-lg leading-8 text-gray-200"> <div><p className="mt-6 text-lg leading-8 text-gray-200">
{question.answer} {question.answer}
</p> </p>
@ -91,7 +99,7 @@ const QuestionView = ({ question, setState, state }: { question: Question, setSt
</button> </button>
</div> </div>
</div> </div>
</Transition> </motion.div>
<Transition <Transition
show={(question && (state.opened[ question.id ])) ? false : true} show={(question && (state.opened[ question.id ])) ? false : true}
enter="transition-opacity duration-300" enter="transition-opacity duration-300"
@ -100,7 +108,7 @@ const QuestionView = ({ question, setState, state }: { question: Question, setSt
leave="transition-opacity duration-150" leave="transition-opacity duration-150"
leaveFrom="opacity-90" leaveFrom="opacity-90"
leaveTo="opacity-0"> leaveTo="opacity-0">
<Button className="text-sm font-semibold leading-6 text-gray-200" onClick={handleOpenClick}> <Button className="leading-6 text-black back rounded-md bg-white text-sm font-semibold text-gray-900" onClick={handleOpenClick} style = {{padding: '5px'}}>
Show answer Show answer
</Button> </Button>
</Transition> </Transition>

View file

@ -1,7 +1,13 @@
import { PlayIcon } from '@heroicons/react/24/outline' 'use client';
import { motion } from 'framer-motion';
import { useState } from 'react';
import LinkButton from './link-button';
const TopicCard = ({ title, children, link }: { title: string, children: any, link: string }) => { const TopicCard = ({ title, children, link }: { title: string, children: any, link: string }) => {
return( const [clicked, setClicked] = useState( false );
<div className="mx-auto mt-16 max-w-2xl rounded-3xl sm:mt-20 lg:mx-0 lg:flex lg:max-w-none relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0" style={{marginTop: '20px', paddingTop: '0px', paddingBottom: '24px'}}> const [hovered, setHovered] = useState( false );
return (
<motion.div className="mx-auto mt-16 max-w-2xl rounded-3xl sm:mt-20 lg:mx-0 lg:flex lg:max-w-none relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0" style={{marginTop: '20px', paddingTop: '0px', paddingBottom: '24px'}}
animate={{x: hovered? 10 : 0, opacity: clicked ? 0.5 : 1 }} onMouseEnter={()=>setHovered(true)} onMouseLeave={()=>setHovered(false)}>
<svg <svg
viewBox="0 0 1024 1024" viewBox="0 0 1024 1024"
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0" className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
@ -25,16 +31,17 @@ const TopicCard = ({ title, children, link }: { title: string, children: any, li
className="-mt-2 p-2 lg:mt-0 lg:max-w-md lg:flex-shrink-0 lg:flex lg:flex-col lg:justify-center" className="-mt-2 p-2 lg:mt-0 lg:max-w-md lg:flex-shrink-0 lg:flex lg:flex-col lg:justify-center"
style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
> >
<a {/* <a
href={link} href={link}
className="rounded-md text-sm font-semibold border text-gray-200 shadow-sm hover:text-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white" className="rounded-md text-sm font-semibold border text-gray-200 shadow-sm hover:text-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ paddingLeft: '50px', paddingRight: '50px', paddingTop: '20px', paddingBottom: '20px'}} style={{ paddingLeft: '50px', paddingRight: '50px', paddingTop: '20px', paddingBottom: '20px'}}
> >
Begin Begin
</a> </a> */}
</div> <LinkButton text="Begin" href={link} onPress={()=>setClicked(true)}/>
</div> </div>
</motion.div>
) )
} }

5
app/lib/delay.ts Normal file
View file

@ -0,0 +1,5 @@
const wait = (time: number): Promise<void> => {
return new Promise( res => setTimeout( res, time ) );
}
export default wait;

View file

@ -1,12 +1,15 @@
'use client';
import { Fragment } from 'react' import { Fragment, useState } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react' import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid' import { ChevronDownIcon } from '@heroicons/react/20/solid'
import Logo from './components/logo'; import Logo from './components/logo';
import { motion } from 'framer-motion';
import LinkButton from './components/link-button';
function classNames(...classes) { function classNames(...classes) {
return classes.filter(Boolean).join(' ') return classes.filter(Boolean).join(' ')
} }
export default function Example() { export default function Example() {
const [buttonPressed, setButtonPressed] = useState( false );
return ( return (
<div> <div>
<div <div
@ -25,10 +28,13 @@ export default function Example() {
<Logo/> <Logo/>
<Transition <Transition
appear={true} appear={true}
show={true} show={!buttonPressed}
enter="transition-opacity duration-500" enter="transition-opacity duration-500"
enterFrom="opacity-0" enterFrom="opacity-0"
enterTo="opacity-80"> enterTo="opacity-80"
leave="transition-opacity duration-150"
leaveFrom="opacity-80"
leaveTo="opacity-0">
<div className="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8"> <div className="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
<div className="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0"> <div className="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
<svg <svg
@ -54,58 +60,18 @@ export default function Example() {
Get questions from a multitude of different subjects that include cybersecurity, geography and C++ Get questions from a multitude of different subjects that include cybersecurity, geography and C++
</p> </p>
<div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start"> <div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
<a {/* <motion.a
href="sessionconfig" href="sessionconfig"
className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white" className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px' }} style={{ marginBottom: '40px' }}
animate={{opacity: buttonHovered ? 0.8 : 1}}
onMouseEnter={()=>setButtonHovered(true)}
onMouseLeave={()=>setButtonHovered(false)}
onClick={()=>setButtonPressed(true)}
> >
Get started Get started
</a> </motion.a> */}
<LinkButton text="Get started" href="/sessionconfig" onPress={()=>setButtonPressed(true)}/>
</div>
</div>
</div>
</div>
</Transition>
<Transition
appear={true}
show={true}
enter="transition-opacity duration-500"
enterFrom="opacity-0"
enterTo="opacity-80">
<div className="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
<div className="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
<svg
viewBox="0 0 1024 1024"
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
aria-hidden="true"
>
<circle cx={512} cy={512} r={512} fill="url(#759c1415-0410-454c-8f7c-9a820de03641)" fillOpacity="0.7" />
<defs>
<radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
<stop stopColor="#7775D6" />
<stop offset={1} stopColor="#E935C1" />
</radialGradient>
</defs>
</svg>
<div className="mx-auto max-w-md text-center lg:mx-0 lg:flex-auto lg:py-32 lg:text-left">
<h2 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">
Start using flash cards
<br />
Begin with our app today.
</h2>
<p className="mt-6 text-lg leading-8 text-gray-300">
Get questions from a multitude of different subjects that include cybersecurity, geography and C++
</p>
<div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
<a
href="sessionconfig"
className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px' }}
>
Get started
</a>
</div> </div>
</div> </div>
</div> </div>