unfinished basic landing page/layout, navbar
This commit is contained in:
parent
09f1dbd607
commit
f2600b7809
8 changed files with 276 additions and 13 deletions
102
components/common/NavBar.tsx
Normal file
102
components/common/NavBar.tsx
Normal 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
37
layouts/HomeLayout.tsx
Normal 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
44
layouts/NavTemplates.tsx
Normal 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 };
|
|
@ -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;
|
||||
|
|
102
pages/index.tsx
102
pages/index.tsx
|
@ -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
BIN
public/img/logo.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
|
@ -3,6 +3,7 @@ module.exports = {
|
|||
content: [
|
||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx}",
|
||||
"./layouts/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
|
|
Loading…
Reference in a new issue