unfinished basic landing page/layout, navbar

This commit is contained in:
3zachm 2022-12-08 07:02:48 -08:00
parent 09f1dbd607
commit f2600b7809
8 changed files with 276 additions and 13 deletions

View file

@ -0,0 +1,102 @@
import Link from "next/link";
import { useState, Fragment } from "react";
import { NavTemplate } from "../../layouts/NavTemplates";
import Image from "next/image";
import { m, Variants } from "framer-motion";
interface NavProps {
options: NavTemplate[];
}
// nav bar animation, fades in and then animates the children
const containerAnimation: Variants = {
initial: {
opacity: 1,
},
animate: {
opacity: 1,
transition: {
duration: 2,
delayChildren: 0.5,
staggerChildren: 0.25,
},
},
};
// default animation for nav bar items
const itemAnimation: Variants = {
initial: {
opacity: 0,
x: 100,
},
animate: {
opacity: 1,
x: 0,
},
};
function NavBar({ options }: NavProps) {
const [navList, setNavList] = useState(options);
return (
<m.div
className="font-Manrope pointer-events-none fixed hidden w-screen justify-between p-7 text-2xl sm:flex"
initial="initial"
animate="animate"
variants={containerAnimation}
>
<m.div variants={itemAnimation}>
<Link
key="InvestBot"
href="/"
className="flex flex-row items-center justify-center"
>
<m.div
initial={{
scale: 1,
rotate: 0,
}}
animate={{
scale: 1,
rotate: 360,
transition: {
duration: 4,
type: "spring",
stiffness: 20,
},
}}
>
<Image
src="/img/logo.webp"
alt="InvestBot Logo"
width={64}
height={64}
className="ml-4 mr-6 rounded-b-full"
/>
</m.div>
<p className="pointer-events-auto select-none pr-5 text-white">
InvestBot
</p>
</Link>
</m.div>
<m.div
className="flex flex-row items-center justify-center"
variants={itemAnimation}
>
{navList.map((nav, index) => (
<Fragment key={index}>{nav.content}</Fragment>
))}
</m.div>
<m.div
className="flex flex-row items-center justify-center"
variants={itemAnimation}
>
<p className="pointer-events-auto select-none pr-5 text-white">
Login blah blah
</p>
<div className="h-10 w-10 rounded-full bg-white"></div>
</m.div>
</m.div>
);
}
export default NavBar;

37
layouts/HomeLayout.tsx Normal file
View file

@ -0,0 +1,37 @@
// Layout/container used for the main mostly empty landing page, can be used for related pages (credits, about, etc.)
import { AnimatePresence, domAnimation, LazyMotion } from "framer-motion";
import Head from "next/head";
import NavBar from "../components/common/NavBar";
import { NavTemplate } from "./NavTemplates";
interface HomeLayoutProps {
navOptions: NavTemplate[];
children: React.ReactNode;
}
function HomeLayout(props: HomeLayoutProps) {
// get the nav options
const navOptions = props.navOptions;
return (
<>
<Head>
<title>InvestBot</title>
<meta name="description" content="Temporary home :)" />
<link rel="icon" href="/favicon.ico" />
</Head>
<LazyMotion features={domAnimation}>
<AnimatePresence exitBeforeEnter>
<NavBar options={navOptions} />
</AnimatePresence>
</LazyMotion>
<LazyMotion features={domAnimation}>
<AnimatePresence exitBeforeEnter>
<div className="h-screen w-screen">{props.children}</div>
</AnimatePresence>
</LazyMotion>
</>
);
}
export default HomeLayout;

44
layouts/NavTemplates.tsx Normal file
View file

@ -0,0 +1,44 @@
import { m } from "framer-motion";
import Link from "next/link";
import { ReactComponentElement, ReactElement } from "react";
const DefaultNavOption = ({
label,
href,
}: {
label: string;
href: string;
}): ReactElement => {
return (
<m.div
initial={{
scale: 1,
}}
whileHover={{
transition: {
duration: 0.2,
},
}}
whileTap={{
scale: 0.95,
transition: {
duration: 0.2,
},
}}
>
<Link href={href} key={label}>
<p className="pointer-events-auto relative select-none pl-3 pr-3 text-white md:pl-5 md:pr-5">
{label}
</p>
</Link>
</m.div>
);
};
interface NavTemplate {
content: ReactComponentElement<any> | ReactElement;
}
const homeMain: NavTemplate[] = [];
export { type NavTemplate, homeMain };

View file

@ -2,6 +2,9 @@
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: ["cdn.discordapp.com", "static-cdn.jtvnw.net", "cdn.7tv.app"],
},
};
module.exports = nextConfig;

View file

@ -1,17 +1,93 @@
import Head from "next/head";
import { m } from "framer-motion";
import { ReactElement, useEffect, useState } from "react";
import HomeLayout from "../layouts/HomeLayout";
import { homeMain } from "../layouts/NavTemplates";
import type { NextPageWithLayout } from "./_app";
import Image from "next/image";
export default function Home() {
return (
<div className="flex h-screen w-screen flex-col items-center justify-center bg-gray-900">
<Head>
<title>InvestBot</title>
<meta name="description" content="Temporary home :)" />
<link rel="icon" href="/favicon.ico" />
</Head>
const Home: NextPageWithLayout = () => {
let api7tvEmotes = `/api/7tv/emotes?c=61ad997effa9aba101bcfddf`;
const [emotesUrls, setEmotes] = useState([]);
const [currentEmote, setCurrentEmote] = useState(0);
useEffect(() => {
fetch(api7tvEmotes)
.then((res) => res.json())
.then((data) => {
// get all emote URLs
let emoteUrls = data.channel.user.emote_sets[0].emotes.map(
(emote: any) => {
let base_url = emote.data.host.url;
// get the largest emote size, append it to the base url
let largest =
emote.data.host.files[emote.data.host.files.length - 1];
// if width != height, skip it
if (largest.width !== largest.height) {
return null;
}
return `https:${base_url}/${largest.name}`;
}
);
<main>
<h1 className="text-6xl text-white">Hello :o</h1>
</main>
</div>
// remove null values
emoteUrls = emoteUrls.filter((emote: any) => emote !== null);
setEmotes(emoteUrls);
console.log(emoteUrls);
});
console.log(currentEmote);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
const interval = setInterval(() => {
// choose a random emote
let randomEmote = Math.floor(Math.random() * emotesUrls.length);
setCurrentEmote(randomEmote);
}, 5000);
return () => clearInterval(interval);
}, [emotesUrls]);
// until the emotes are loaded, show the logo as a placeholder
let slideShow = (
<Image
src="/img/logo.webp"
alt="InvestBot Logo"
width={128}
height={128}
className="ml-4 mr-6"
/>
);
if (emotesUrls) {
slideShow = (
<Image
src={emotesUrls[currentEmote]}
alt="7tv emote"
width={128}
height={128}
className="ml-4 mr-6"
/>
);
}
return (
<div className="flex h-full w-full flex-col items-center justify-center bg-zinc-900">
<div className="flex text-white">
<div className="flex flex-col">
<m.h1 className="font-Manrope m-2 text-7xl">Buy high</m.h1>
<m.h1 className="font-Manrope m-2 text-7xl">Sell low</m.h1>
<m.h2 className="pt-2">...or something like that</m.h2>
</div>
<div className="flex items-center">{slideShow}</div>
</div>
</div>
);
};
// set the layout for the page, this is used to wrap the page in a layout
Home.getLayout = function getLayout(page: ReactElement) {
return <HomeLayout navOptions={homeMain}>{page}</HomeLayout>;
};
export default Home;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
public/img/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -3,6 +3,7 @@ module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./layouts/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},