improvements on navbar color shift functionality

This commit is contained in:
2023-06-12 08:39:52 -05:00
parent 36a8930a1b
commit 45fce4eaf2
5 changed files with 155 additions and 136 deletions

View File

@@ -1,77 +0,0 @@
'use client'
import { useEffect, useState } from "react";
import { DefaultColors } from "tailwindcss/types/generated/colors";
const LOOPING_ENABLED_ON_SECOND_LOGO = true;
const SHIFT_INTERVAL = 3000;
export default function LogoPage() {
const [circleColors, setCircleColors] = useState<{ [key: string]: typeof colorList[number] | "" }>({
firstColor: "",
secondColor: "",
thirdColor: "",
})
const colorList: (`bg-${keyof DefaultColors}` | `bg-${keyof DefaultColors}-${string}`)[] = [
"bg-purple-400",
"bg-purple-700",
"bg-sky-400",
"bg-sky-700",
"bg-blue-400",
"bg-pink-400",
"bg-pink-700",
];
function handleHover() {
const firstColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
const secondColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
const thirdColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
setCircleColors({ firstColor, secondColor, thirdColor });
}
useEffect(handleHover, []);
useEffect(() => {
if (LOOPING_ENABLED_ON_SECOND_LOGO) {
const interval = setInterval(() => {
handleHover();
}, SHIFT_INTERVAL);
return () => clearInterval(interval);
}
}, [])
return (
<main>
<h1>Logo</h1>
<div id="venn-diagram-logo-container" className="flex w-full h-auto justify-center">
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col z-40 items-center justify-center animate-logo-throw-left h-[150px] w-[150px] bg-opacity-75 ${circleColors.firstColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100">M</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col items-center justify-center animate-logo-throw-down h-[150px] w-[150px] bg-opacity-75 ${circleColors.secondColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100 z-50">C</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col items-center justify-center animate-logo-throw-right h-[150px] w-[150px] bg-opacity-75 ${circleColors.thirdColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100">D</p>
</div>
</div>
<div id="inline-logo-container" className="flex w-full h-auto justify-center mt-[25rem]">
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col items-center justify-center h-[150px] w-[150px] bg-opacity-75 ${circleColors.firstColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-6xl font-bold opacity-100">M</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col -ml-8 items-center justify-center h-[150px] w-[150px] bg-opacity-75 ${circleColors.secondColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-6xl font-bold opacity-100">C</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col -ml-8 items-center justify-center h-[150px] w-[150px] bg-opacity-75 ${circleColors.thirdColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-6xl font-bold opacity-100">D</p>
</div>
</div>
</main>
)
}

View File

@@ -1,21 +0,0 @@
import Link from 'next/link'
import { InlineLogo } from './logo'
export default function Navbar() {
return (
<div id="navbar" className="w-full h-auto flex flex-nowrap justify-between px-8 py-4 bg-black text-white">
<Link href="/">
<InlineLogo />
</Link>
<Link href="/about">
<p>About</p>
</Link>
<Link href="/projects">
<p>Projects</p>
</Link>
<Link href="/contact">
<p>Contact</p>
</Link>
</div>
)
}

View File

@@ -0,0 +1,94 @@
import Link from 'next/link'
import { InlineLogo, useColorShift } from '../logo'
import { useEffect, useState } from 'react';
import { UseColorShiftReturnType } from '../logo/useColorShift';
interface HoverState {
about: boolean
projects: boolean
contact: boolean
}
const SHIFT_INTERVAL = 3000;
export default function Navbar() {
const navbarColorShift = useColorShift(SHIFT_INTERVAL);
const { shift } = navbarColorShift;
const [colors, setColors] = useState<Partial<UseColorShiftReturnType>>({
firstColor: 'bg-inherit',
secondColor: 'bg-inherit',
thirdColor: 'bg-inherit',
});
const [hoverState, setHoverState] = useState<HoverState>({
about: false,
projects: false,
contact: false,
})
function mouseOver(source: keyof HoverState) {
const { colorKeys, actualColorReferences, activeIndex } = identifyActiveButton();
setColors({ ...colors, [colorKeys[activeIndex]]: actualColorReferences[activeIndex] });
setHoverState({ ...hoverState, [source]: true })
}
function mouseOut(source: keyof HoverState) {
setHoverState({ ...hoverState, [source]: false })
setColors({ firstColor: 'bg-inherit', secondColor: 'bg-inherit', thirdColor: 'bg-inherit' });
}
function identifyActiveButton() {
const buttonKeys: (keyof HoverState)[] = ['about', 'projects', 'contact'];
const { firstColor, secondColor, thirdColor } = navbarColorShift;
const colorKeys = ['firstColor', 'secondColor', 'thirdColor'];
const actualColorReferences = [firstColor, secondColor, thirdColor];
const activeButton = buttonKeys.find(key => hoverState[key]);
const activeIndex = buttonKeys.indexOf(activeButton as keyof HoverState);
return { colorKeys, actualColorReferences, activeIndex };
}
useEffect(() => {
const interval = setInterval(shift, SHIFT_INTERVAL);
return () => clearInterval(interval);
}, [])
useEffect(() => {
const interval = setInterval(() => {
const { colorKeys, actualColorReferences, activeIndex } = identifyActiveButton();
for (const key in hoverState) {
if (hoverState[key as keyof HoverState]) {
setColors({
...colors,
[colorKeys[activeIndex]]: actualColorReferences[activeIndex]
});
}
}
}, 1000);
return () => clearInterval(interval);
}, [shift])
return (
<div id="navbar" className="w-full h-auto flex flex-nowrap items-center justify-between px-8 py-4 bg-black text-white">
<Link href="/">
<InlineLogo customHookInstance={navbarColorShift} />
</Link>
<Link href="/about" onMouseOver={() => mouseOver('about')} onMouseOut={() => mouseOut('about')} className={`${colors.firstColor} rounded-lg transition-colors ease-out duration-${hoverState.about ? '[5000ms]' : '0'}`}>
<p className='text-lg text-white text-opacity-80 hover:text-opacity-100 uppercase border-white border-2 p-2 rounded-lg border-opacity-50 hover:border-opacity-75'>About</p>
</Link>
<Link href="/projects" onMouseOver={() => mouseOver("projects")} onMouseOut={() => mouseOut('projects')} className={`${colors.secondColor} rounded-lg transition-colors ease-out duration-${hoverState.projects ? '[5000ms]' : '0'}`}>
<p className='text-lg text-white text-opacity-80 hover:text-opacity-100 hover:border-opacity-75 uppercase border-white border-2 p-2 rounded-lg border-opacity-50'>Projects</p>
</Link>
<Link href="/contact" onMouseOver={() => mouseOver('projects')} onMouseOut={() => mouseOut('projects')} className={`${colors.thirdColor} rounded-lg transition-colors ease-out duration-${hoverState.contact ? '[5000ms]' : '0'}`}>
<p className='text-lg text-white text-opacity-80 hover:text-opacity-100 uppercase border-white border-2 p-2 rounded-lg border-opacity-50 hover:border-opacity-75'>Contact</p>
</Link>
</div>
)
}

View File

@@ -1,6 +1,6 @@
'use client'
import { FC } from "react";
import useColorShift, { type ColorListType } from "./useColorShift";
import useColorShift, { UseColorShiftReturnType, type ColorListType } from "./useColorShift";
import { useRouter } from "next/navigation";
export { default as useColorShift } from "./useColorShift";
@@ -10,33 +10,34 @@ interface LogoProps {
shiftInterval?: number,
customColorList?: ColorListType[],
disableShift?: boolean,
customHookInstance?: UseColorShiftReturnType
}
export const StackedLogo: FC<LogoProps> = ({ shiftInterval, customColorList, disableShift = false }) => {
export const StackedLogo: FC<LogoProps> = ({ shiftInterval, customColorList, customHookInstance, disableShift = false }) => {
const hookProps = [
shiftInterval ?? DEFAULT_SHIFT_INTERVAL,
disableShift,
customColorList,
] as const;
const { firstColor, secondColor, thirdColor, handleHover } = useColorShift(...hookProps);
const { firstColor, secondColor, thirdColor, shift } = useColorShift(...hookProps);
return (
<div id="venn-diagram-logo-container" className="flex w-full h-auto justify-center">
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col z-40 items-center justify-center animate-logo-throw-left h-16 w-16 bg-opacity-75 ${firstColor} transition-colors duration-[5000ms] ease rounded-full`}>
<div onMouseEnter={shift} onMouseOut={shift} className={`absolute flex flex-col z-40 items-center justify-center animate-logo-throw-left h-16 w-16 bg-opacity-75 ${firstColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100">M</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col items-center justify-center animate-logo-throw-down h-16 w-16 bg-opacity-75 ${secondColor} transition-colors duration-[5000ms] ease rounded-full`}>
<div onMouseEnter={shift} onMouseOut={shift} className={`absolute flex flex-col items-center justify-center animate-logo-throw-down h-16 w-16 bg-opacity-75 ${secondColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100 z-50">C</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`absolute flex flex-col items-center justify-center animate-logo-throw-right h-16 w-16 bg-opacity-75 ${thirdColor} transition-colors duration-[5000ms] ease rounded-full`}>
<div onMouseEnter={shift} onMouseOut={shift} className={`absolute flex flex-col items-center justify-center animate-logo-throw-right h-16 w-16 bg-opacity-75 ${thirdColor} transition-colors duration-[5000ms] ease rounded-full`}>
<p className="text-6xl font-bold opacity-100">D</p>
</div>
</div>
)
}
export const InlineLogo: FC<LogoProps> = ({ shiftInterval, customColorList, disableShift = false }) => {
export const InlineLogo: FC<LogoProps> = ({ shiftInterval, customColorList, customHookInstance, disableShift = false }) => {
const router = useRouter();
const hookProps = [
@@ -45,19 +46,35 @@ export const InlineLogo: FC<LogoProps> = ({ shiftInterval, customColorList, disa
customColorList,
] as const;
const { firstColor, secondColor, thirdColor, handleHover } = useColorShift(...hookProps);
const { firstColor, secondColor, thirdColor, shift } = useColorShift(...hookProps);
return (
if (customHookInstance) return (
<button onClick={() => router.push('/')} id="inline-logo-container" className="flex w-auto h-auto justify-center">
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col items-center justify-center h-16 w-16 bg-opacity-75 ${firstColor} transition-colors duration-[5000ms] rounded-full`}>
<div className={`flex flex-col items-center justify-center h-16 w-16 bg-opacity-75 ${customHookInstance.firstColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">M</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${secondColor} transition-colors duration-[5000ms] rounded-full`}>
<div className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${customHookInstance.secondColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">C</p>
</div>
<div onMouseEnter={handleHover} onMouseOut={handleHover} className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${thirdColor} transition-colors duration-[5000ms] rounded-full`}>
<div className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${customHookInstance.thirdColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">D</p>
</div>
</button>
)
return (
<button onClick={() => router.push('/')} id="inline-logo-container" className="flex w-auto h-auto justify-center">
<div className={`flex flex-col items-center justify-center h-16 w-16 bg-opacity-75 ${firstColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">M</p>
</div>
<div className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${secondColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">C</p>
</div>
<div className={`flex flex-col -ml-3 items-center justify-center h-16 w-16 bg-opacity-75 ${thirdColor} transition-colors duration-[5000ms] rounded-full`}>
<p className="text-2xl font-bold opacity-100">D</p>
</div>
</button>

View File

@@ -1,57 +1,63 @@
import { useEffect, useState } from "react";
import { DefaultColors } from "tailwindcss/types/generated/colors";
export type ColorListType = (`bg-${keyof DefaultColors}` | `bg-${keyof DefaultColors}-${string}`);
export type ColorListType = (`bg-${keyof DefaultColors}` | `bg-${keyof DefaultColors}-${string}` | "");
const colorList: ColorListType[] = [
"bg-purple-400",
"bg-purple-700",
"bg-sky-400",
"bg-sky-700",
"bg-blue-400",
"bg-pink-400",
"bg-pink-700",
"bg-purple-500",
"bg-purple-800",
"bg-sky-500",
"bg-sky-800",
"bg-blue-500",
"bg-pink-500",
"bg-pink-800",
];
const useColorShift = (shiftInterval: number, disableShift = false, customColorList?: ColorListType[]): {
firstColor: ColorListType | "",
secondColor: ColorListType | "",
thirdColor: ColorListType | "",
handleHover: () => void,
} => {
if (shiftInterval <= 0) throw new Error("shiftInterval must be greater than 0")
export interface UseColorShiftReturnType {
firstColor: ColorListType
secondColor: ColorListType
thirdColor: ColorListType
shift: () => { firstColor: ColorListType, secondColor: ColorListType, thirdColor: ColorListType }
shiftInterval: number | undefined
}
const useColorShift = (shiftInterval?: number, disableShift = false, customColorList?: ColorListType[]): UseColorShiftReturnType => {
if (shiftInterval && shiftInterval <= 0) throw new Error("shiftInterval must be greater than 0")
const randomColor = () => (customColorList ?? colorList)[Math.floor(Math.random() * colorList.length | 0)];
const [circleColors, setCircleColors] = useState<{
firstColor: ColorListType | "",
secondColor: ColorListType | "",
thirdColor: ColorListType | "",
}>({
firstColor: "",
secondColor: "",
thirdColor: "",
firstColor: colorList[0],
secondColor: colorList[1],
thirdColor: colorList[2],
})
function handleHover() {
const firstColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
const secondColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
const thirdColor = colorList[Math.floor(Math.random() * colorList.length | 0)]
function shift() {
const firstColor = randomColor();
const secondColor = randomColor();
const thirdColor = randomColor();
setCircleColors({ firstColor, secondColor, thirdColor });
return { firstColor, secondColor, thirdColor };
}
// perform initial mount of color changing pattern
useEffect(disableShift ? handleHover : (() => { return }), []);
useEffect(disableShift ? shift : (() => { return }), []);
// set this function to repeat
useEffect(() => {
const interval = setInterval(() => {
handleHover();
}, shiftInterval);
shift();
}, shiftInterval ?? 3000);
return () => clearInterval(interval);
}, [])
return { ...circleColors, handleHover };
return { ...circleColors, shift, shiftInterval };
}
export default useColorShift