Finished animations
This commit is contained in:
parent
7198551a63
commit
91bd54a8a2
6 changed files with 78 additions and 64 deletions
26
app/components/link-button.tsx
Normal file
26
app/components/link-button.tsx
Normal 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;
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
5
app/lib/delay.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const wait = (time: number): Promise<void> => {
|
||||||
|
return new Promise( res => setTimeout( res, time ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
export default wait;
|
68
app/page.tsx
68
app/page.tsx
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue