Skip to content

Commit

Permalink
feat: Complete Layout Design (pbclife#13)
Browse files Browse the repository at this point in the history
* style: designed scroll-bar

* build: added styling dependency

* build: updated module import/export

* style: updated progress-color

* feat: added menu section

* style: added new variables to theme

* refactor: separated theme-button from navbar

* feat: added links to menu

* style: git opener logo updated

* feat: created some utility components
  • Loading branch information
sboy99 committed Jan 13, 2023
1 parent 662bd38 commit c571ca2
Show file tree
Hide file tree
Showing 20 changed files with 498 additions and 48 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@tailwindcss/typography": "^0.5.8",
"autoprefixer": "^10.4.13",
"clsx": "^1.2.1",
"framer-motion": "^8.4.2",
"gray-matter": "^4.0.3",
"husky": "^8.0.2",
"mini-svg-data-uri": "^1.4.4",
Expand Down
2 changes: 1 addition & 1 deletion src/components/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import GradientBG from '../utilities/gradient-bg';

export default function Header() {
return (
<div className="relative border-b border-skin-base ">
<div className="relative overflow-hidden">
<Navbar />
<div className="pointer-events-none absolute inset-0 -z-10 bg-dot-slate-500/30 [mask-image:linear-gradient(-90deg,white,rgba(255,255,255,0))]"></div>
<div className="pointer-events-none absolute inset-0 -z-20 bg-gradient-to-br from-primary via-primary/90 to-primary/50 backdrop-blur-md"></div>
Expand Down
7 changes: 3 additions & 4 deletions src/components/icons/git-opener.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ const GitOpenerIcon = (props: Props) => {
return (
<svg
role="img"
viewBox="0 0 190 218"
viewBox="0 0 100 100"
{...props}
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
xmlns="http:https://www.w3.org/2000/svg"
>
<title>GitOpener</title>
<path d="M189.067 54.69 95 .382.934 54.691v108.618L95 217.619l94.067-54.31V54.691ZM80.441 18.025l14.56-8.405 15.438 8.913.002 56.698c-.172 1.977-7.31 6.644-15.002 9.912-7.691-3.262-14.809-7.926-14.994-9.896l-.004-57.222Zm-6.464 3.732L8.934 59.31v99.382L95 208.381l86.067-49.69V59.309l-64.162-37.044.002 52.979c-.003 2.276-1.326 4.467-3.334 6.475-3.917 3.917-10.448 7.159-14.9 9.077v43.877c5.547 1.439 9.657 6.49 9.662 12.48l-.004 29.502c0 3.44-1.34 6.679-3.775 9.113a12.802 12.802 0 0 1-9.113 3.775 12.79 12.79 0 0 1-9.115-3.774 12.798 12.798 0 0 1-3.772-9.117l-.007-29.496c.005-5.781 4.235-10.935 9.658-12.448l.002-43.912c-6.734-2.898-18.23-8.834-18.228-15.55l-.004-53.49ZM95.534 140.73l.042-.001c3.477.073 6.29 2.93 6.294 6.431l-.003 29.496c-.003 3.429-2.997 6.423-6.424 6.423a6.37 6.37 0 0 1-4.543-1.881 6.379 6.379 0 0 1-1.88-4.545l-.008-29.49a6.402 6.402 0 0 1 1.888-4.549 6.398 6.398 0 0 1 4.408-1.885l.132.002.094-.001Z"></path>
<path d="M80,50c-5.521,0-10,4.479-10,10c0,4.346,2.793,8.008,6.667,9.388v2.946L53.333,82.705V72.663L65,67.478V52.038l8.333-3.705 v-7.279C77.207,39.676,80,36.012,80,31.667c0-5.521-4.479-10-10-10s-10,4.479-10,10c0,4.346,2.793,8.01,6.667,9.388V44l-8.334,3.705 v15.442l-5,2.224V29.388C57.207,28.009,60,24.347,60,20c0-5.522-4.479-10-10-10c-5.522,0-10,4.478-10,10 c0,4.347,2.792,8.009,6.667,9.388v27.714l-13.333-8.886v-3.828C37.207,43.009,40,39.347,40,35c0-5.522-4.479-10-10-10 s-10,4.478-10,10c0,4.347,2.793,8.009,6.667,9.388v7.396l20,13.33V90h6.667l30-13.333v-7.279C87.207,68.008,90,64.346,90,60 C90,54.479,85.521,50,80,50z M70,28.333c1.843,0,3.333,1.491,3.333,3.333C73.333,33.509,71.843,35,70,35s-3.333-1.491-3.333-3.333 C66.667,29.824,68.157,28.333,70,28.333z M30,38.333c-1.842,0-3.333-1.493-3.333-3.333s1.491-3.333,3.333-3.333 s3.333,1.493,3.333,3.333S31.842,38.333,30,38.333z M50,23.333c-1.842,0-3.333-1.493-3.333-3.333s1.491-3.333,3.333-3.333 c1.843,0,3.333,1.493,3.333,3.333S51.843,23.333,50,23.333z M80,63.333c-1.843,0-3.333-1.49-3.333-3.333s1.49-3.333,3.333-3.333 s3.333,1.49,3.333,3.333S81.843,63.333,80,63.333z"></path>
<path d="M29.665,65.771C29.863,64.987,30,64.18,30,63.333c0-5.521-4.479-10-10-10s-10,4.479-10,10c0,5.521,4.479,10,10,10 c2.245,0,4.295-0.768,5.965-2.018l7.368,4.912V90H40V72.659L29.665,65.771z M20,66.667c-1.842,0-3.333-1.491-3.333-3.334 C16.667,61.491,18.158,60,20,60s3.333,1.491,3.333,3.333C23.333,65.176,21.842,66.667,20,66.667z"></path>
</svg>
);
};
Expand Down
9 changes: 7 additions & 2 deletions src/components/layouts/main.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Footer from '@components/footer';
import Header from '@components/header';
import Menu from '@components/menu';
import Head from 'next/head';
import React from 'react';
import Footer from '../footer';
import Header from '../header';

export type LayoutProps = React.HTMLAttributes<HTMLDivElement> & {
children: React.ReactNode;
Expand All @@ -25,6 +26,10 @@ const Layout: React.FC<LayoutProps> = ({
</Head>
<div {...props}>
<Header />
{/* Menu */}
<div className="sticky top-0">
<Menu />
</div>
{/* outlet */}
<div className="bg-skin-base">{children}</div>
<Footer />
Expand Down
110 changes: 110 additions & 0 deletions src/components/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import Glow from '@utilities/glow';
import Logo from '@utilities/logo';
import { AnimatePresence, Variants, motion } from 'framer-motion';
import { FC, useEffect, useState } from 'react';
import Container from '../layouts/container';
import ThemeButton from '../navbar/theme-button';
import MenuList from './menu-list';

export default function Menu() {
const [isSticky, setIsSticky] = useState<boolean>(false);
useEffect(() => {
function handleScroll() {
const scrollTop = window.scrollY;

if (scrollTop >= 53) {
setIsSticky(true);
} else {
setIsSticky(false);
}
}
window.addEventListener('scroll', handleScroll);

return () => window.removeEventListener('scroll', handleScroll);
}, []);

const displayLogoVarient: Variants = {
initial: {
opacity: 0,
transition: {
duration: 0.8,
ease: 'easeInOut',
},
scale: 0.5,
},
onEnter: {
opacity: 1,
scale: 0.95,
},
onExit: {
opacity: 0,
scale: 0.65,
},
};
const displayIconVarient: Variants = {
initial: {
opacity: 0,
transition: {
duration: 0.8,
ease: 'easeInOut',
},
scale: 0.5,
rotate: 150,
},
onEnter: {
opacity: 1,
scale: 1,
rotate: 360,
transition: {
delay: 0.25,
},
},
onExit: {
opacity: 0,
scale: 0.65,
},
};

function getAnimComp(Comp: FC, varient: Variants, key: string) {
return (
<AnimatePresence>
{isSticky && (
<motion.div
variants={varient}
key={key}
initial={`initial`}
animate={`onEnter`}
exit={`onExit`}
className="flex items-center gap-x-12 "
>
<Comp />
</motion.div>
)}
</AnimatePresence>
);
}

const displayLogo = getAnimComp(Logo, displayLogoVarient, `displayLogo`);
const displayIcon = getAnimComp(
ThemeButton,
displayIconVarient,
`displayIcon`
);

return (
<div className="relative w-full border-b border-skin-base bg-skin-base text-skin-base ">
<Glow className="sm:right-0 sm:max-w-3xl " />
<Container className="relative z-0 flex min-h-[4rem] flex-col items-center justify-end sm:min-h-[5rem] sm:flex-row sm:justify-between">
{/* upper section */}
<div className="z-10 flex items-center gap-x-12">
{displayLogo}
{displayIcon}
</div>
{/* links section */}
<div className="z-0 sm:self-end">
<MenuList />
</div>
</Container>
</div>
);
}
28 changes: 28 additions & 0 deletions src/components/menu/menu-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { links } from '@/data/menu-links';
import Link from 'next/link';
import { useRouter } from 'next/router';
import ToolTip from '../utilities/tooltip';

export default function MenuList() {
const { pathname } = useRouter();
return (
<ul className="flex items-center ">
{links.map((link, indx) => {
const isActive: boolean = pathname === link.to;
return (
<Link href={link.to} key={link.title + indx}>
<li
className={`border-b-2 px-4 py-2 text-lg font-semibold capitalize tracking-tight transition-all duration-300 ease-in-out hover:text-accent
${isActive ? ` border-accent text-accent ` : `border-transparent`}
`}
>
<ToolTip tip={link.title}>
<link.icon className="h-6 w-6" />
</ToolTip>
</li>
</Link>
);
})}
</ul>
);
}
19 changes: 4 additions & 15 deletions src/components/navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import GitOpenerIcon from '@/components/icons/git-opener';
import { useThemeContext } from '@/context/theme-context';
import { MoonIcon, SunIcon } from '@heroicons/react/24/solid';
import Container from '@layouts/container';
import Pop from '@utilities/pop';
import Themes from './theme';
import Logo from '@utilities/logo';
import ThemeButton from './theme-button';

export default function Navbar() {
const { isDark } = useThemeContext();
return (
<Container className="z-10 flex items-center justify-between">
{/* logo */}
<div className="flex items-center gap-x-2 py-4 text-skin-base">
<GitOpenerIcon className="h-10 w-10 rotate-90 " />
<span className="text-2xl font-bold tracking-tight">Git Opener</span>
</div>
<Logo />
{/* social icons */}
<div className="">
<Pop Icon={isDark ? MoonIcon : SunIcon} className="!z-50">
<Themes />
</Pop>
</div>
<ThemeButton />
</Container>
);
}
15 changes: 15 additions & 0 deletions src/components/navbar/theme-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useThemeContext } from '@/context/theme-context';
import { MoonIcon, SunIcon } from '@heroicons/react/24/solid';
import Pop from '@utilities/pop';
import Themes from './theme';

export default function ThemeButton() {
const { isDark } = useThemeContext();
return (
<div className="">
<Pop Icon={isDark ? MoonIcon : SunIcon} className="!z-50">
<Themes />
</Pop>
</div>
);
}
140 changes: 140 additions & 0 deletions src/components/utilities/glow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { useThemeContext } from '@/context/theme-context';
import React, { useEffect, useId, useState } from 'react';
import colors from 'tailwindcss/colors';

interface GlowType {
className: string;
}

const Glow: React.FC<GlowType> = ({ className }) => {
const id = useId();
const [from, setFrom] = useState<string>(``);
const [to, setTo] = useState<string>(``);
const { isDark } = useThemeContext();

useEffect(() => {
if (isDark) {
setFrom(colors.pink[500]);
setTo(colors.fuchsia[400]);
} else {
setFrom(colors.blue[500]);
setTo(colors.sky[500]);
}
}, [isDark]);

return (
<svg
viewBox="0 0 384 12"
fill="none"
aria-hidden="true"
className={`!pointer-events-none absolute top-full w-full transition ${className}`}
>
<mask
id={`${id}-a`}
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x={48}
y={0}
width={269}
height={4}
>
<path
transform="rotate(180 316.656 4)"
fill="#C4C4C4"
d="M316.656 4h268v4h-268z"
/>
</mask>
<g filter={`url(#${id}-b)`} mask={`url(#${id}-a)`}>
<path
transform="rotate(180 292.656 1)"
fill={`url(#${id}-c)`}
d="M292.656 1h220v2h-220z"
/>
</g>
<mask
id={`${id}-d`}
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x={116}
y={0}
width={268}
height={12}
>
<path
transform="rotate(180 384 12)"
fill="#C4C4C4"
d="M384 12h268v12H384z"
/>
</mask>
<g filter={`url(#${id}-e)`} mask={`url(#${id}-d)`}>
<path
transform="rotate(180 360 1)"
fill={`url(#${id}-f)`}
d="M360 1h220v2H360z"
/>
</g>
<defs>
<linearGradient
id={`${id}-c`}
x1="292.656"
y1={1}
x2="512.656"
y2={1}
gradientUnits="userSpaceOnUse"
>
<stop stopColor={from} stopOpacity={0} />
<stop offset=".323" stopColor={from} />
<stop offset=".672" stopColor={to} stopOpacity=".3" />
<stop offset={1} stopColor={to} stopOpacity={0} />
</linearGradient>
<linearGradient
id={`${id}-f`}
x1={360}
y1={1}
x2={580}
y2={1}
gradientUnits="userSpaceOnUse"
>
<stop stopColor={from} stopOpacity={0} />
<stop offset=".323" stopColor={from} />
<stop offset=".672" stopColor={to} stopOpacity=".3" />
<stop offset={1} stopColor={to} stopOpacity={0} />
</linearGradient>
<filter
id={`${id}-b`}
x="71.656"
y={-2}
width={222}
height={4}
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity={0} result="BackgroundImageFix" />
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur
stdDeviation=".5"
result="effect1_foregroundBlur_311_43467"
/>
</filter>
<filter
id={`${id}-e`}
x={131}
y={-10}
width={238}
height={20}
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity={0} result="BackgroundImageFix" />
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur
stdDeviation="4.5"
result="effect1_foregroundBlur_311_43467"
/>
</filter>
</defs>
</svg>
);
};

export default Glow;
Loading

0 comments on commit c571ca2

Please sign in to comment.