Merge pull request #1 from jackmerrill/devel/redesign-tailwind-ui
Redesign with TailwindUI
52
.breakpoints
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"files": {
|
||||
"components/Navbar.tsx": [
|
||||
{
|
||||
"id": "5aa0d634-c476-4ab2-9957-d364b66311b2",
|
||||
"line": 4,
|
||||
"version": 1719,
|
||||
"index": 217
|
||||
},
|
||||
{
|
||||
"id": "01e112b0-3705-4b70-bf88-5b2716dd492d",
|
||||
"line": 86,
|
||||
"version": 1719,
|
||||
"index": 3326
|
||||
}
|
||||
],
|
||||
"components/Projects.tsx": [
|
||||
{
|
||||
"id": "f1084f0b-cb32-4b05-b4a3-02d058b717b2",
|
||||
"line": 15,
|
||||
"version": 1242,
|
||||
"index": 512
|
||||
},
|
||||
{
|
||||
"id": "57d95fae-f14a-4006-9f32-bbe9021aa156",
|
||||
"line": 90,
|
||||
"version": 1242,
|
||||
"index": 3381
|
||||
},
|
||||
{
|
||||
"id": "d35f19ba-4d8c-488b-8a38-a26540595f2d",
|
||||
"line": 91,
|
||||
"version": 1242,
|
||||
"index": 3396
|
||||
}
|
||||
],
|
||||
"pages/index.tsx": [
|
||||
{
|
||||
"id": "d3363946-0aa7-43f5-b2ee-bc23387ea7a5",
|
||||
"line": 14,
|
||||
"version": 1196,
|
||||
"index": 609
|
||||
},
|
||||
{
|
||||
"id": "91f8cc38-eb3c-426c-ba37-749bb88281ac",
|
||||
"line": 90,
|
||||
"version": 1196,
|
||||
"index": 3779
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import NextJSIcon from "./Images/NextJSIcon";
|
|||
import TailwindIcon from "./Images/TailwindIcon";
|
||||
|
||||
const Footer = () => (
|
||||
<footer className='flex flex-wrap justify-center text-center w-full bg-gray-900 p-8'>
|
||||
<footer className='flex flex-wrap justify-center border-t-2 border-white text-center w-full bg-black p-8'>
|
||||
<p className='flex w-full items-center justify-center text-white font-bold text-lg space-x-1'>
|
||||
Made with
|
||||
<HeartIcon className='text-red-500 md:h-6 md:w-6 h-12 w-12 ml-1' />
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
const Logo = () => (
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 1080 1080"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
xmlSpace="preserve"
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
strokeLinejoin='round'
|
||||
strokeMiterlimit='2'
|
||||
>
|
||||
<g transform="matrix(1.87667,0,0,1.87667,-211.69,-370.379)">
|
||||
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||
</g>
|
||||
<g transform="matrix(1.87667,0,0,1.87667,-45.877,-370.379)">
|
||||
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||
</g>
|
||||
<g transform="matrix(1.87667,0,0,1.87667,119.936,-370.379)">
|
||||
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||
</g>
|
||||
<g transform="matrix(1.87667,0,0,1.87667,-473.399,-473.402)">
|
||||
<path d="M362.424,611.832L534.257,439.76C540.749,433.259 551.297,433.252 557.798,439.744C564.299,446.235 564.306,456.784 557.815,463.285L381.105,640.24C379.514,641.833 377.679,643.037 375.72,643.85L375.686,643.864C373.726,644.676 371.578,645.124 369.326,645.124L268.899,645.124C259.712,645.124 252.253,637.665 252.253,628.478C252.253,619.29 259.712,611.832 268.899,611.832L362.424,611.832Z" fill="white" />
|
||||
const Logo = (props: any) => (
|
||||
<svg width="100%" height="100%" viewBox="0 0 1080 1080" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" xmlSpace="preserve" fillRule="evenodd" clipRule="evenodd" strokeLinejoin="round" strokeMiterlimit="2" {...props}>
|
||||
<g>
|
||||
<g transform="matrix(2.37095,0,0,2.37095,-437.8,-886.233)">
|
||||
<g transform="matrix(-1,-1.22465e-16,1.22465e-16,-1,563.619,1290.65)">
|
||||
<path d="M333.908,553.8L378.967,643.918L288.85,643.918L333.908,553.8Z" fill="rgb(235,235,235)"/>
|
||||
</g>
|
||||
<path d="M410.08,466.234L475.099,466.234L339.788,736.855L274.769,736.855L410.08,466.234Z" fill="rgb(235,235,235)"/>
|
||||
</g>
|
||||
<g transform="matrix(-2.37095,0,0,2.37095,1624.63,-886.233)">
|
||||
<g transform="matrix(1,0,0,1,-59.1395,92.9335)">
|
||||
<path d="M333.908,553.8L378.967,643.918L288.85,643.918L333.908,553.8Z" fill="rgb(235,235,235)"/>
|
||||
</g>
|
||||
<g transform="matrix(-1,0,0,1,749.868,0)">
|
||||
<path d="M410.08,466.234L475.099,466.234L339.788,736.855L274.769,736.855L410.08,466.234Z" fill="rgb(235,235,235)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,16 +1,34 @@
|
|||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import { MenuIcon, XIcon } from '@heroicons/react/outline'
|
||||
|
||||
const Navbar = ({ links }: {
|
||||
links: {
|
||||
label: string;
|
||||
href: string;
|
||||
}[]
|
||||
}) => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
import Logo from '../components/Images/Logo';
|
||||
|
||||
const navigation = [
|
||||
{ name: 'Home', href: '#', current: true },
|
||||
{ name: 'About', href: '#about', current: false },
|
||||
{ name: 'Projects', href: '#projects', current: false },
|
||||
{ name: 'Graphics', href: '#graphics', current: false },
|
||||
{ name: 'Contact', href: '#contact', current: false },
|
||||
];
|
||||
|
||||
function classNames(...classes: any[]) {
|
||||
return classes.filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
const Navbar = ({ views }: { views: { view: string, viewing: boolean }[] }) => {
|
||||
const [atTop, setAtTop] = useState<boolean>()
|
||||
|
||||
function updateCurrent() {
|
||||
const currentlyViewing = views.find((view) => view.viewing === true)
|
||||
navigation.forEach((nav) => nav.current = false)
|
||||
if (currentlyViewing) {
|
||||
const nav = navigation.find((nav) => nav.name === currentlyViewing.view)
|
||||
if (!nav) return
|
||||
nav.current = true
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (window.scrollY === 0) {
|
||||
setAtTop(true)
|
||||
|
@ -23,47 +41,80 @@ const Navbar = ({ links }: {
|
|||
} else {
|
||||
setAtTop(false)
|
||||
}
|
||||
|
||||
updateCurrent()
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<nav className={`fixed w-full flex flex-wrap items-center justify-between px-2 py-6 navbar-expand-lg z-30 bg-gray-800 ${atTop ? '' : 'shadow-md'}`}>
|
||||
<div className="container px-4 mx-auto flex flex-wrap items-center justify-between">
|
||||
<div className="w-full relative flex justify-between md:w-auto px-4 md:static md:block md:justify-start items-center">
|
||||
<div className="text-sm font-bold leading-relaxed inline-block mr-4 py-2 whitespace-no-wrap text-white">
|
||||
<Link href="/" aria-label="Stryx Logo">
|
||||
<h1 className="text-white font-extrabold text-2xl">Jack Merrill</h1>
|
||||
</Link>
|
||||
</div>
|
||||
<button className="md:hidden text-gray-500 w-10 h-10 relative focus:outline-none" onClick={() => setCollapsed(!collapsed)}>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<div className="block w-5 absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed ? 'rotate-45' : '-translate-y-1.5' }`} />
|
||||
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed && 'opacity-0'}`} ></span>
|
||||
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed ? '-rotate-45' : 'translate-y-1.5' }`} ></span>
|
||||
return (
|
||||
<Disclosure as="nav" className={`fixed w-full z-50 bg-black border-b-2 border-white ${atTop ? '' : 'shadow-lg'}`}>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<div className="px-4 mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<Logo className="w-8 h-8" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className={`md:flex flex-grow items-center md:opacity-1 transition-fadeDown transform ease-in-out ${collapsed ? '-translate-y-1 h-0 opacity-0' : 'translate-y-1 opacity-1 h-10'}`} id="navbar">
|
||||
<ul className="flex list-none ml-auto items-center">
|
||||
{links.map(({ label, href }) => (
|
||||
<li className="nav-item">
|
||||
<div className="px-3 py-2 flex items-center leading-snug text-white">
|
||||
<Link href={href} passHref>
|
||||
<a
|
||||
className="font-bold text-gray-200 hover:underline"
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
</Link>
|
||||
<div className="hidden md:block">
|
||||
<div className="flex items-baseline ml-10 space-x-4">
|
||||
{navigation.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
id={item.name + item.href}
|
||||
onClick={() => {
|
||||
updateCurrent()
|
||||
}}
|
||||
className={classNames(
|
||||
item.current
|
||||
? 'border-2 border-white text-white'
|
||||
: 'text-gray-300 hover:border-gray-300 hover:border-2 hover:text-white',
|
||||
'px-3 py-2 rounded-md text-sm font-medium transition-border duration-75'
|
||||
)}
|
||||
aria-current={item.current ? 'page' : undefined}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex -mr-2 md:hidden">
|
||||
{/* Mobile menu button */}
|
||||
<Disclosure.Button className="inline-flex items-center justify-center p-2 text-gray-400 bg-gray-800 rounded-md hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white">
|
||||
<span className="sr-only">Open main menu</span>
|
||||
{open ? (
|
||||
<XIcon className="block w-6 h-6" aria-hidden="true" />
|
||||
) : (
|
||||
<MenuIcon className="block w-6 h-6" aria-hidden="true" />
|
||||
)}
|
||||
</Disclosure.Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
|
||||
<Disclosure.Panel className="md:hidden">
|
||||
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
|
||||
{navigation.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className={classNames(
|
||||
item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
|
||||
'block px-3 py-2 rounded-md text-base font-medium'
|
||||
)}
|
||||
aria-current={item.current ? 'page' : undefined}
|
||||
>
|
||||
{item.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar;
|
95
components/Projects.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
const projects = [
|
||||
{
|
||||
title: 'Lunar Design',
|
||||
href: 'https://github.com/DesignByLunar',
|
||||
category: { name: 'Organization', color: 'bg-indigo-100 text-indigo-800' },
|
||||
description:
|
||||
'American counterpart of the French-American duo making software that\'s out of this world.',
|
||||
},
|
||||
{
|
||||
title: 'BlueJay',
|
||||
href: 'https://bluejay.one',
|
||||
category: { name: 'SaaS', color: 'bg-blue-100 text-blue-800' },
|
||||
description:
|
||||
'Amazing Ro-Tech solutions for everyone, completely free.',
|
||||
},
|
||||
{
|
||||
title: 'Snacc.chat',
|
||||
href: 'https://snacc.chat',
|
||||
category: { name: 'CodeDay', color: 'bg-red-100 text-red-800' },
|
||||
description:
|
||||
'A social network made in 24 hours at CodeDay.',
|
||||
},
|
||||
{
|
||||
title: 'SCP Mobile',
|
||||
href: 'https://github.com/jackmerrill/SCP-Mobile',
|
||||
category: { name: 'CodeDay', color: 'bg-red-100 text-red-800' },
|
||||
description:
|
||||
'Mobile (iOS) app for the SCP Wiki. Made in 24 hours at CodeDay.',
|
||||
},
|
||||
{
|
||||
title: 'Family Guy Quotes bot',
|
||||
href: 'https://github.com/jackmerrill/FamilyGuyQuotesBot',
|
||||
category: { name: 'Project', color: 'bg-purple-100 text-purple-800' },
|
||||
description:
|
||||
'Uses Discord slash commands to send random Family Guy quotes.',
|
||||
},
|
||||
{
|
||||
title: 'OOFS',
|
||||
href: 'https://github.com/oofs-project/oofs',
|
||||
category: { name: 'Project', color: 'bg-purple-100 text-purple-800' },
|
||||
description:
|
||||
'Online Orientated File Storage. Made in 24 hours at CodeDay. Won Best in Show.',
|
||||
},
|
||||
]
|
||||
|
||||
function classNames(...classes: any) {
|
||||
return classes.filter(Boolean).join(' ')
|
||||
}
|
||||
|
||||
export default function Projects() {
|
||||
return (
|
||||
<div className="text-white pt-16 pb-20 px-4 sm:px-6 lg:pt-24 lg:pb-28 lg:px-8">
|
||||
<div className="relative max-w-lg mx-auto divide-y-2 divide-gray-200 lg:max-w-7xl">
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-3xl tracking-tight font-extrabold text-gray-50 sm:text-4xl">Recent projects</h2>
|
||||
<p className="mt-3 text-xl text-gray-200 sm:mt-4">
|
||||
Here's what I've been working on!
|
||||
</p>
|
||||
<h2 className="text-2xl tracking-tight font-bold text-gray-50 sm:text-3xl">Current Job</h2>
|
||||
<p className="mt-3 text-lg text-gray-200 sm:mt-4">
|
||||
UX Engineer / Web Developer for
|
||||
{' '}
|
||||
<a href="https://merch.co" className="text-blue-400 font-bold" target="_blank">
|
||||
Merch
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-12 grid gap-16 pt-12 lg:grid-cols-3 lg:gap-x-5 lg:gap-y-12">
|
||||
{projects.map((project) => (
|
||||
<div key={project.title}>
|
||||
<div>
|
||||
<div className="inline-block">
|
||||
<span
|
||||
className={classNames(
|
||||
project.category.color,
|
||||
'inline-flex items-center px-3 py-0.5 rounded-full text-sm font-medium'
|
||||
)}
|
||||
>
|
||||
{project.category.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href={project.href} target="_blank" className="block mt-4">
|
||||
<p className="text-xl font-semibold text-gray-50">{project.title}</p>
|
||||
<p className="mt-3 text-base text-gray-200">{project.description}</p>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="w-full text-center font-bold py-6">Looking for more? <a className="text-blue-100" href="https://github.com/jackmerrill" target="_blank">Check my GitHub.</a></p>
|
||||
</div>
|
||||
)
|
||||
}
|
78
components/Skills.tsx
Normal file
|
@ -0,0 +1,78 @@
|
|||
import { PencilIcon, CodeIcon, ServerIcon } from '@heroicons/react/outline'
|
||||
|
||||
const links = [
|
||||
{
|
||||
name: 'Web Development',
|
||||
href: '#projects',
|
||||
description:
|
||||
'I\'ve used Next.js, Express.js, and Flask for backends, and TailwindCSS, Bootstrap, and Material Design for frontends.',
|
||||
icon: CodeIcon,
|
||||
},
|
||||
{
|
||||
name: 'Server Management',
|
||||
href: '#projects',
|
||||
description:
|
||||
'I have lots of experience with managing servers, whether they are on-premises or cloud servers. I have experience using and managing Docker instances as well as databases.',
|
||||
icon: ServerIcon,
|
||||
},
|
||||
{
|
||||
name: 'Graphic Design',
|
||||
href: '#graphics',
|
||||
description:
|
||||
'My front-end experience stemmed from my graphic design skills. I have used Adobe Illustrator, Affinity Designer, Inkscape, and other graphic programs.',
|
||||
icon: PencilIcon,
|
||||
},
|
||||
]
|
||||
|
||||
export default function Skills() {
|
||||
function calculateAge() {
|
||||
var ageDifMs = Date.now() - new Date('July 13, 2004').getTime();
|
||||
var ageDate = new Date(ageDifMs);
|
||||
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-black" id="about" >
|
||||
{/* Header */}
|
||||
<div className="relative pb-32">
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute inset-0 mix-blend-multiply" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="relative max-w-7xl mx-auto py-24 px-4 sm:py-32 sm:px-6 lg:px-8">
|
||||
<h1 className="text-4xl font-extrabold tracking-tight text-white md:text-5xl lg:text-6xl">Hey there!</h1>
|
||||
<p className="mt-6 max-w-3xl text-xl text-gray-300">
|
||||
I'm Jack, a {calculateAge()} year old web developer from Chicago. I've been programming since 2014 creating great things with Javascript, Python, HTML and CSS, and more.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overlapping cards */}
|
||||
<section
|
||||
className="-mt-32 max-w-7xl mx-auto relative z-10 pb-32 px-4 sm:px-6 lg:px-8"
|
||||
aria-labelledby="contact-heading"
|
||||
>
|
||||
<h2 className="sr-only" id="contact-heading">
|
||||
My Skills
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 gap-y-20 lg:grid-cols-3 lg:gap-y-0 lg:gap-x-8">
|
||||
{links.map((link) => (
|
||||
<div key={link.name} className="flex flex-col bg-white rounded-2xl shadow-xl">
|
||||
<div className="flex-1 relative pt-16 px-6 pb-8 md:px-8">
|
||||
<div className="absolute top-0 p-5 inline-block bg-indigo-600 rounded-xl shadow-lg transform -translate-y-1/2">
|
||||
<link.icon className="h-6 w-6 text-white" aria-hidden="true" />
|
||||
</div>
|
||||
<h3 className="text-xl font-medium text-gray-900">{link.name}</h3>
|
||||
<p className="mt-4 text-base text-gray-500">{link.description}</p>
|
||||
</div>
|
||||
<div className="p-6 bg-gray-50 rounded-bl-2xl rounded-br-2xl md:px-8">
|
||||
<a href={link.href} className="text-base font-medium text-indigo-700 hover:text-indigo-600">
|
||||
See more<span aria-hidden="true"> →</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -8,6 +8,8 @@
|
|||
"type-check": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.1",
|
||||
"@heroicons/react": "^1.0.4",
|
||||
"framer-motion": "^4.1.2",
|
||||
"next": "^10.1.3",
|
||||
"next-page-transitions": "^1.0.0-beta.2",
|
||||
|
|
|
@ -1,43 +1,23 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import React from 'react'
|
||||
import { AppProps } from 'next/app'
|
||||
import SEO from '../next-seo.config';
|
||||
import { DefaultSeo } from 'next-seo';
|
||||
import 'tailwindcss/tailwind.css'
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Navbar from '../components/Navbar';
|
||||
import Footer from '../components/Footer';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleStart = () => {
|
||||
setLoading(true);
|
||||
}
|
||||
const handleComplete = () => {
|
||||
setTimeout(() => setLoading(false), 300)
|
||||
}
|
||||
|
||||
router.events.on('routeChangeStart', handleStart)
|
||||
router.events.on('routeChangeComplete', handleComplete)
|
||||
router.events.on('routeChangeError', handleComplete)
|
||||
})
|
||||
|
||||
return <>
|
||||
<div id='app'>
|
||||
<main className="bg-gray-800 w-full h-full min-h-screen">
|
||||
<div id='loader' className={`flex justify-center items-center align-middle fixed dark:bg-gray-800 ${loading ? 'h-screen w-screen z-50 opacity-100' : 'z-10 opacity-0'} transform transition-all duration-300`} />
|
||||
<Navbar links={[
|
||||
{ label: 'Home', href: '/' },
|
||||
{ label: 'My Work', href: '#projects' },
|
||||
{ label: 'Designs', href: '#designs' },
|
||||
]} />
|
||||
<main className="w-full h-full min-h-screen bg-black">
|
||||
<DefaultSeo {...SEO}/>
|
||||
<Component {...pageProps} />
|
||||
<Footer />
|
||||
</main>
|
||||
<style jsx global>{`
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
|
||||
return initialProps
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang='en'>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
265
pages/index.tsx
|
@ -1,18 +1,72 @@
|
|||
import Link from 'next/link'
|
||||
import Image from 'next/image';
|
||||
import { useEffect, useState } from 'react'
|
||||
import CodeIcon from '../components/Images/CodeIcon'
|
||||
import DesignIcon from '../components/Images/DesignIcon'
|
||||
import { useEffect, useState, useRef } from 'react'
|
||||
import GitHubIcon from '../components/Images/GitHubIcon';
|
||||
import MailIcon from '../components/Images/MailIcon';
|
||||
import TwitterIcon from '../components/Images/TwitterIcon';
|
||||
import Head from 'next/head';
|
||||
|
||||
import Navbar from '../components/Navbar';
|
||||
import Skills from '../components/Skills';
|
||||
import Projects from '../components/Projects';
|
||||
import useOnScreen from '../util/hooks/useOnScreen';
|
||||
|
||||
const Graphics = [
|
||||
{
|
||||
name: 'Personal Logo',
|
||||
src: '/img/designs/NewPersonalLogo.png',
|
||||
},
|
||||
{
|
||||
name: 'Old Personal Logo',
|
||||
src: '/img/designs/PersonalLogo.png',
|
||||
},
|
||||
{
|
||||
name: 'Demo App Icon',
|
||||
src: '/img/designs/AppIcon.png',
|
||||
},
|
||||
{
|
||||
name: 'Stryx Logo',
|
||||
src: '/img/designs/Stryx.png',
|
||||
},
|
||||
{
|
||||
name: 'Isometric Building',
|
||||
src: '/img/designs/IsometricBuilding.png',
|
||||
},
|
||||
{
|
||||
name: 'AmusedGrape Icon',
|
||||
src: '/img/designs/Grape.png',
|
||||
},
|
||||
{
|
||||
name: 'New Stryx Icon',
|
||||
src: '/img/designs/StryxNew.png',
|
||||
},
|
||||
{
|
||||
name: 'Nyxx Logo',
|
||||
src: '/img/designs/Nyxx.png',
|
||||
},
|
||||
{
|
||||
name: 'Lunar Design Logo',
|
||||
src: '/img/designs/LunarDesign.png',
|
||||
},
|
||||
];
|
||||
|
||||
const IndexPage = () => {
|
||||
const [timeString, setTimeString] = useState(
|
||||
(new Date().getHours() < 12 ? 'Morning' : (new Date().getHours() >= 12 && new Date().getHours() <= 17 ? 'Afternoon' : (new Date().getHours() >= 17 && new Date().getHours() <= 24 ? 'Evening' : 'Morning')))
|
||||
)
|
||||
|
||||
const homeRef = useRef(null);
|
||||
const aboutRef = useRef(null);
|
||||
const graphicsRef = useRef(null);
|
||||
const projectsRef = useRef(null);
|
||||
const contactRef = useRef(null);
|
||||
|
||||
const viewingHome = useOnScreen(homeRef)
|
||||
const viewingAbout = useOnScreen(aboutRef)
|
||||
const viewingGraphics = useOnScreen(graphicsRef)
|
||||
const viewingProjects = useOnScreen(projectsRef)
|
||||
const viewingContact = useOnScreen(contactRef)
|
||||
|
||||
useEffect(() => {
|
||||
const hours = new Date().getHours()
|
||||
|
||||
|
@ -38,212 +92,87 @@ const IndexPage = () => {
|
|||
<Head>
|
||||
<meta name='description' content='Graphic Designer and Fullstack Developer.' />
|
||||
</Head>
|
||||
<header className="flex flex-wrap flex-col overflow-hidden space-y-2 lg:px-36 items-center justify-center h-screen w-full">
|
||||
<div className="my-3 px-3 w-full text-center">
|
||||
<h1 className="text-white font-extrabold md:text-6xl text-3xl">Good <span className="text-blue-500">{timeString}</span>! I'm <span className="text-purple-500">Jack Merrill</span>.</h1>
|
||||
<Navbar views={[
|
||||
{ view: 'Home', viewing: viewingHome },
|
||||
{ view: 'About', viewing: viewingAbout },
|
||||
{ view: 'Projects', viewing: viewingProjects },
|
||||
{ view: 'Graphics', viewing: viewingGraphics },
|
||||
{ view: 'Contact', viewing: viewingContact },
|
||||
]} />
|
||||
<header className="flex flex-col flex-wrap items-center justify-center w-full h-screen space-y-2 overflow-hidden lg:px-36" ref={homeRef}>
|
||||
<div className="w-full px-3 my-3 text-center">
|
||||
<h1 className="text-3xl font-extrabold text-white md:text-6xl">Good <span>{timeString}</span>! I'm <span>Jack Merrill</span>.</h1>
|
||||
</div>
|
||||
<div className="my-3 px-3 w-full text-center">
|
||||
<h2 className="text-white font-bold md:text-4xl text-2xl">A {calculateAge()} year old Graphic and UI Designer and Fullstack Developer from the Windy City.</h2>
|
||||
<div className="w-full px-3 my-3 text-center">
|
||||
<h2 className="text-2xl font-bold text-white md:text-4xl">A {calculateAge()} year old Graphic and UI Designer and Fullstack Developer from the Windy City.</h2>
|
||||
</div>
|
||||
<div className="inline-flex flex-wrap md:space-y-0 space-y-4 pt-4 items-center justify-center content-center md:space-x-4 my-3 px-3 w-full text-center">
|
||||
<div className="inline-flex flex-wrap items-center content-center justify-center w-full px-3 pt-4 my-3 space-y-4 text-center md:space-y-0 md:space-x-4">
|
||||
<Link href="#projects">
|
||||
<a className="bg-gradient-to-r from-green-400 to-blue-500 px-4 py-2 rounded-xl font-bold text-white md:w-1/6 w-full">
|
||||
<a className="w-full px-4 py-2 font-bold text-white truncate transition duration-150 border border-white hover:bg-white hover:text-black rounded-xl md:w-1/6">
|
||||
See my Work
|
||||
</a>
|
||||
</Link>
|
||||
<span className="text-sm font-light text-gray-400 md:block hidden">or</span>
|
||||
<span className="hidden text-sm font-light text-white md:block">or</span>
|
||||
<Link href="mailto:me@jackmerrill.com">
|
||||
<a className="bg-gradient-to-r from-green-400 to-blue-500 px-4 py-2 rounded-xl font-bold text-white md:w-1/6 w-full">
|
||||
<a className="w-full px-4 py-2 font-bold text-white transition duration-150 border border-white hover:bg-white hover:text-black rounded-xl md:w-1/6">
|
||||
Contact Me
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
<div className='bg-gradient-to-b from-purple-600 to-purple-700 h-full lg:max-h-96'>
|
||||
<div className='flex flex-wrap py-16 px-4 p lg:p-16 space-y-6'>
|
||||
<div className='w-full overflow-hidden'>
|
||||
<h1 className='text-white text-4xl font-bold text-center'>Nice to meet you!</h1>
|
||||
</div>
|
||||
<div className='w-full px-12 lg:px-48'>
|
||||
<p className='text-white text-2xl text-center'>
|
||||
I'm Jack, a {calculateAge()} year old Graphic/UI Designer and Fullstack Developer from Chicago. Since I started
|
||||
programming in 2014, I've used Python, NodeJS, HTML and CSS. Nowadays, I prefer to
|
||||
use NextJS, TailwindCSS, and NodeJS. Being a fullstack developer, I've
|
||||
had to create numerous logos and brands for various projects of mine.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div ref={aboutRef} id="about">
|
||||
<Skills />
|
||||
</div>
|
||||
<div className='-mt-10'>
|
||||
<div className='flex flex-wrap lg:px-64 lg:space-y-0 px-12 space-y-6'>
|
||||
<div className='flex flex-wrap justify-center text-center py-12 lg:w-1/2 w-full min-h-96 max-h-full space-y-2 bg-white rounded-xl lg:rounded-l-xl lg:rounded-r-none border shadow-lg'>
|
||||
<div className='w-full flex flex-wrap justify-center'>
|
||||
<CodeIcon className='h-36 text-green-500 rounded-full bg-gray-100 p-5' />
|
||||
</div>
|
||||
<div className='w-full space-y-3 px-6'>
|
||||
<h1 className='text-gray-800 font-bold text-2xl'>Fullstack Developer</h1>
|
||||
<p className='text-gray-800 text-xl font-light'>I strive to make great things.</p>
|
||||
<h2 className='text-purple-500 font-bold text-xl'>What I've made:</h2>
|
||||
<p className='text-gray-800 text-lg font-light'>SaaS applications, Image websites, Social Networks</p>
|
||||
<h2 className='text-purple-500 font-bold text-xl'>Tools I use:</h2>
|
||||
<ol>
|
||||
<li className='text-gray-800 text-lg font-light'>Next.js</li>
|
||||
<li className='text-gray-800 text-lg font-light'>Node.js / Express</li>
|
||||
<li className='text-gray-800 text-lg font-light'>MongoDB</li>
|
||||
<li className='text-gray-800 text-lg font-light'>PostgreSQL</li>
|
||||
<li className='text-gray-800 text-lg font-light'>Docker</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-wrap justify-center text-center my-px py-12 lg:w-1/2 w-full min-h-96 max-h-full space-y-2 bg-white rounded-xl lg:rounded-r-xl lg:rounded-l-none border shadow-lg'>
|
||||
<div className='w-full flex flex-wrap justify-center'>
|
||||
<DesignIcon className='h-36 text-green-500 rounded-full bg-gray-100 p-5' />
|
||||
</div>
|
||||
<div className='w-full space-y-3 px-6'>
|
||||
<h1 className='text-gray-800 font-bold text-2xl'>Graphic and UI Design</h1>
|
||||
<p className='text-gray-800 text-xl font-light'>I like to create designs and brands.</p>
|
||||
<h2 className='text-purple-500 font-bold text-xl'>What I enjoy designing:</h2>
|
||||
<p className='text-gray-800 text-lg font-light'>Brands, Logos, Banners, Headers</p>
|
||||
<h2 className='text-purple-500 font-bold text-xl'>Tools I use:</h2>
|
||||
<ol>
|
||||
<li className='text-gray-800 text-lg font-light'>Affinity Designer</li>
|
||||
<li className='text-gray-800 text-lg font-light'>Figma</li>
|
||||
<li className='text-gray-800 text-lg font-light'>TailwindCSS</li>
|
||||
<li className='text-gray-800 text-lg font-light'>Bootstrap</li>
|
||||
<li className='text-gray-800 text-lg font-light'>React.js</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='projects' className='flex flex-wrap justify-center px-12 lg:px-64 pt-24 space-y-3'>
|
||||
<h1 className='w-full font-bold text-white text-center text-3xl'>My recent work</h1>
|
||||
<p className='w-full font-semibold text-white text-center text-xl'>Here are a few projects I've been working on!</p>
|
||||
<div className="flex flex-wrap w-full -mx-1 overflow-hidden justify-center">
|
||||
|
||||
<div className="flex my-1 w-full overflow-hidden rounded-xl relative h-36">
|
||||
{/* <Image alt='Stryx Photo' layout='fill' src='/img/Stryx.png' objectFit='cover' objectPosition='top' className='absolute rounded-xl filter blur-xl' /> */}
|
||||
<div className='flex flex-wrap items-center content-center justify-end w-full h-full text-right transition transform duration-200 p-12 space-y-2'>
|
||||
<h1 className='w-full text-white font-bold text-3xl'>Lunar Design</h1>
|
||||
<p className='w-full text-white font-light text-xs'>American counterpart of the French-American duo making software that's out of this world.</p>
|
||||
<a className='flex bg-green-500 items-center justify-center px-2 py-1 rounded-xl text-white w-2/3 sm:w-1/3' href='https://github.com/designbylunar/' target='_blank' rel='noreferrer'>Visit</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex my-1 w-full overflow-hidden rounded-xl relative h-36">
|
||||
<Image alt='Stryx Photo' layout='fill' src='/img/Stryx.png' objectFit='cover' objectPosition='top' className='absolute rounded-xl filter blur-xl' />
|
||||
<div className='flex flex-wrap items-center content-center justify-end w-full h-full text-right transition transform duration-200 p-12 space-y-2'>
|
||||
<h1 className='w-full text-white font-bold text-3xl'>Stryx</h1>
|
||||
<p className='w-full text-white font-light text-xs'>Roblox Group Management made easy (defunct, no long associated)</p>
|
||||
<a className='flex bg-green-500 items-center justify-center px-2 py-1 rounded-xl text-white w-2/3 sm:w-1/3' href='https://stryx.cloud' target='_blank' rel='noreferrer'>Visit</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex my-1 w-full overflow-hidden rounded-xl relative h-36">
|
||||
<Image alt='Snacc.chat Photo' layout='fill' src='/img/Snacc.chat.png' objectFit='cover' objectPosition='top' className='absolute rounded-xl filter blur-xl' />
|
||||
<div className='flex flex-wrap items-center content-center justify-end w-full h-full text-right transition transform duration-200 p-12 space-y-2'>
|
||||
<h1 className='w-full text-white font-bold text-3xl'>Snacc.chat</h1>
|
||||
<p className='w-full text-white font-light text-xs'>Made in 24 hours at <a className='font-bold' href='https://codeday.org' target='_blank' rel='noreferrer'>CodeDay</a>, Snacc.chat is a simple social network for programmers alike.</p>
|
||||
<a className='flex bg-green-500 items-center justify-center px-2 py-1 rounded-xl text-white w-2/3 sm:w-1/3' href='https://snacc.chat' target='_blank' rel='noreferrer'>Visit</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex my-1 w-full overflow-hidden rounded-xl relative h-36">
|
||||
<Image alt='FRCMS Docs Photo' layout='fill' src='/img/FRCMS.png' objectFit='cover' objectPosition='top' className='absolute rounded-xl filter blur-xl' />
|
||||
<div className='flex flex-wrap items-center content-center justify-end w-full h-full text-right transition transform duration-200 p-12 space-y-2'>
|
||||
<h1 className='w-full text-white font-bold text-3xl'>FRCMS</h1>
|
||||
<p className='w-full text-white font-light text-xs'>FIRST Robotics CMS (WIP)</p>
|
||||
<a className='flex bg-green-500 items-center justify-center px-2 py-1 rounded-xl text-white w-2/3 sm:w-1/3' href='https://dev.frcms.app' target='_blank' rel='noreferrer'>Visit</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex my-1 w-full overflow-hidden rounded-xl relative h-36">
|
||||
<Image alt='Ricky.cat Photo' layout='fill' src='/img/Ricky.cat.png' objectFit='cover' objectPosition='top' className='absolute rounded-xl filter blur-xl' />
|
||||
<div className='flex flex-wrap items-center content-center justify-end w-full h-full text-right transition transform duration-200 p-12 space-y-2'>
|
||||
<h1 className='w-full text-white font-bold text-3xl'>Ricky.cat</h1>
|
||||
<p className='w-full text-white font-light text-xs'>My first Next.js project! A place to share my cat. Discontinued (for now).</p>
|
||||
<a className='flex bg-green-500 items-center justify-center px-2 py-1 rounded-xl text-white w-2/3 sm:w-1/3' href='https://ricky.cat' target='_blank' rel='noreferrer'>Visit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='projects' ref={projectsRef}>
|
||||
<Projects />
|
||||
</div>
|
||||
|
||||
<div id='designs' className='flex flex-wrap justify-center px-12 lg:px-64 pt-24 space-y-3'>
|
||||
<h1 className='w-full font-bold text-white text-center text-3xl'>My Designs</h1>
|
||||
<p className='w-full font-semibold text-white text-center text-xl'>Here are a few designs I've made!</p>
|
||||
<div className="flex flex-wrap w-full -mx-1 overflow-hidden justify-center">
|
||||
<div id='graphics' className='flex flex-wrap justify-center px-12 pt-24 space-y-3 lg:px-64' ref={graphicsRef}>
|
||||
<h1 className='w-full text-3xl font-bold text-center text-white'>My Designs</h1>
|
||||
<p className='w-full text-xl font-semibold text-center text-white'>Here are a few designs I've made!</p>
|
||||
<div className="flex flex-wrap justify-center w-full -mx-1 overflow-hidden">
|
||||
<div className="flex flex-wrap -mx-3 overflow-hidden">
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Personal Logo' width='1080px' height='1080px' src='/img/designs/PersonalLogo.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Demo App Icon' width='1080px' height='1080px' src='/img/designs/AppIcon.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Stryx Logo' width='1080px' height='1080px' src='/img/designs/Stryx.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Comet Design' width='1080px' height='1080px' src='/img/designs/Comet.png' className='rounded-xl bg-gray-600' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Isometric Building Design' width='1080px' height='1080px' src='/img/designs/IsometricBuilding.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Grape Logo' width='1080px' height='1080px' src='/img/designs/Grape.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='New Stryx Logo' width='1080px' height='1080px' src='/img/designs/StryxNew.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Nyxx Logo' width='1080px' height='1080px' src='/img/designs/Nyxx.png' className='rounded-xl' />
|
||||
</div>
|
||||
|
||||
<div className="my-3 px-3 w-1/2 md:w-1/3 overflow-hidden">
|
||||
<Image alt='Lunar Design Logo' width='1080px' height='1080px' src='/img/designs/LunarDesign.png' className='rounded-xl' />
|
||||
</div>
|
||||
{Graphics.map((gfx) => (
|
||||
<div className="w-1/2 px-3 my-3 overflow-hidden md:w-1/3">
|
||||
<Image alt={gfx.name} width='1080px' height='1080px' src={gfx.src} className='rounded-xl' />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='contact' className='flex flex-wrap justify-center p-12 space-y-4'>
|
||||
<h1 className='text-white font-bold text-3xl'>Want to contact me?</h1>
|
||||
<div className='flex align-middle justify-center w-full'>
|
||||
<div id='contact' className='flex flex-wrap justify-center p-12 space-y-4' ref={contactRef}>
|
||||
<h1 className='text-3xl font-bold text-white'>Want to contact me?</h1>
|
||||
<div className='flex justify-center w-full align-middle'>
|
||||
<a
|
||||
href='https://github.com/jackmerrill'
|
||||
target='_blank'
|
||||
className='flex justify-center items-center px-10 py-4 w-11/12 lg:w-1/4 bg-github rounded-xl text-white font-bold text-xl'
|
||||
className='flex items-center justify-center w-11/12 px-10 py-4 text-xl font-bold text-white lg:w-1/4 bg-github rounded-xl'
|
||||
rel='noreferrer'
|
||||
>
|
||||
<GitHubIcon className='text-white h-6 w-6 mr-3'/>
|
||||
<GitHubIcon className='w-6 h-6 mr-3 text-white'/>
|
||||
GitHub Profile
|
||||
</a>
|
||||
</div>
|
||||
<div className='flex align-middle justify-center w-full'>
|
||||
<div className='flex justify-center w-full align-middle'>
|
||||
<a
|
||||
href='mailto:me@jackmerrill.com'
|
||||
target='_blank'
|
||||
className='flex justify-center items-center px-10 py-4 w-11/12 lg:w-1/4 bg-gray-900 rounded-xl text-white font-bold text-xl'
|
||||
className='flex items-center justify-center w-11/12 px-10 py-4 text-xl font-bold text-white bg-gray-900 lg:w-1/4 rounded-xl'
|
||||
rel='noreferrer'
|
||||
>
|
||||
<MailIcon className='text-white h-6 w-6 mr-3'/>
|
||||
<MailIcon className='w-6 h-6 mr-3 text-white'/>
|
||||
Email
|
||||
</a>
|
||||
</div>
|
||||
<div className='flex align-middle justify-center w-full'>
|
||||
<div className='flex justify-center w-full align-middle'>
|
||||
<a
|
||||
href='https://twitter.com/jack__merrill'
|
||||
target='_blank'
|
||||
className='flex justify-center items-center px-10 py-4 w-11/12 lg:w-1/4 bg-twitter rounded-xl text-white font-bold text-xl'
|
||||
className='flex items-center justify-center w-11/12 px-10 py-4 text-xl font-bold text-white lg:w-1/4 bg-twitter rounded-xl'
|
||||
rel='noreferrer'
|
||||
>
|
||||
<TwitterIcon className='text-white h-6 w-6 mr-3'/>
|
||||
<TwitterIcon className='w-6 h-6 mr-3 text-white'/>
|
||||
Twitter
|
||||
</a>
|
||||
</div>
|
||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 27 KiB |
BIN
public/img/designs/NewPersonalLogo.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
|
@ -16,12 +16,15 @@ module.exports = {
|
|||
'twitter': '#1DA1F2',
|
||||
},
|
||||
transitionProperty: {
|
||||
'fadeDown': 'height opacity'
|
||||
'fadeDown': 'height opacity',
|
||||
'border': 'border-width border-color'
|
||||
}
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
|
||||
extend: {
|
||||
borderWidth: ['hover']
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('tailwindcss-filters'),
|
||||
|
|
20
util/hooks/useOnScreen.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default function useOnScreen(ref: any) {
|
||||
|
||||
let observer: any = null
|
||||
|
||||
const [isIntersecting, setIntersecting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
observer = new IntersectionObserver(
|
||||
([entry]) => setIntersecting(entry.isIntersecting)
|
||||
)
|
||||
|
||||
observer.observe(ref.current)
|
||||
// Remove the observer as soon as the component is unmounted
|
||||
return () => { observer.disconnect() }
|
||||
}, [])
|
||||
|
||||
return isIntersecting
|
||||
}
|
10
yarn.lock
|
@ -97,6 +97,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.1.tgz#9daf5745156fd84b8e9889a2dc721f0c58e894aa"
|
||||
integrity sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw==
|
||||
|
||||
"@headlessui/react@^1.4.1":
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.4.1.tgz#0a8dbb20e1d63dcea55bfc3ab1b87637aaac7777"
|
||||
integrity sha512-gL6Ns5xQM57cZBzX6IVv6L7nsam8rDEpRhs5fg28SN64ikfmuuMgunc+Rw5C1cMScnvFM+cz32ueVrlSFEVlSg==
|
||||
|
||||
"@heroicons/react@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.4.tgz#11847eb2ea5510419d7ada9ff150a33af0ad0863"
|
||||
integrity sha512-3kOrTmo8+Z8o6AL0rzN82MOf8J5CuxhRLFhpI8mrn+3OqekA6d5eb1GYO3EYYo1Vn6mYQSMNTzCWbEwUInb0cQ==
|
||||
|
||||
"@next/env@10.1.3":
|
||||
version "10.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-10.1.3.tgz#29e5d62919b4a7b1859f8d36169848dc3f5ddebe"
|
||||
|
|