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 = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
|
images: {
|
||||||
|
domains: ["cdn.discordapp.com", "static-cdn.jtvnw.net", "cdn.7tv.app"],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
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";
|
||||||
|
|
||||||
|
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}`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen w-screen flex-col items-center justify-center bg-gray-900">
|
<div className="flex h-full w-full flex-col items-center justify-center bg-zinc-900">
|
||||||
<Head>
|
<div className="flex text-white">
|
||||||
<title>InvestBot</title>
|
<div className="flex flex-col">
|
||||||
<meta name="description" content="Temporary home :)" />
|
<m.h1 className="font-Manrope m-2 text-7xl">Buy high</m.h1>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<m.h1 className="font-Manrope m-2 text-7xl">Sell low</m.h1>
|
||||||
</Head>
|
<m.h2 className="pt-2">...or something like that</m.h2>
|
||||||
|
</div>
|
||||||
<main>
|
<div className="flex items-center">{slideShow}</div>
|
||||||
<h1 className="text-6xl text-white">Hello :o</h1>
|
</div>
|
||||||
</main>
|
|
||||||
</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: [
|
content: [
|
||||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||||
"./components/**/*.{js,ts,jsx,tsx}",
|
"./components/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./layouts/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
|
|
Loading…
Reference in a new issue