Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
@import url("https://fonts.googleapis.com/css2?family=Niconne&display=swap")
layer(base);

@import "tailwindcss";

@config "../tailwind.config.js";

@theme {
--font-cursive: "Niconne", "ui-cursive", "cursive";
@theme inline {
--font-cursive: var(--font-niconne), "ui-cursive", "cursive";
}

html {
Expand All @@ -21,3 +18,38 @@ html[data-scroll="true"] .scroll-show {
html[data-scroll="true"] .scroll-hide {
opacity: 0;
}

/* fade cards up as they scroll into view, where supported */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
@keyframes reveal {
from {
opacity: 0;
transform: translateY(3rem);
}
}

.reveal {
animation: reveal linear both;
animation-timeline: view();
animation-range: cover 0% cover 40%;
}
}
}

/* subtle zoom on the hero photo as it scrolls away, where supported */
@supports (animation-timeline: scroll()) {
@media (prefers-reduced-motion: no-preference) {
@keyframes hero-zoom {
to {
transform: scale(1.1);
}
}

.hero-zoom {
animation: hero-zoom linear both;
animation-timeline: scroll(root);
animation-range: 0 100vh;
}
}
}
10 changes: 9 additions & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Niconne } from "next/font/google";
import type { ReactElement, ReactNode } from "react";
import ScrollProvider from "../components/scroll";
import ThemeProvider from "../components/theme";
import "./globals.css";

const niconne = Niconne({
weight: "400",
subsets: ["latin"],
variable: "--font-niconne",
display: "swap",
});

export default function RootLayout({
children,
}: {
children: ReactNode;
}): ReactElement {
return (
<html lang="en">
<html lang="en" className={niconne.variable}>
<body>
<ScrollProvider />
<ThemeProvider>{children}</ThemeProvider>
Expand Down
103 changes: 80 additions & 23 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import hafa from "../images/hafa.svg";
import splash from "../images/irina-shishkina-FMlZAUFmkvw-unsplash.jpg";
import repub from "../images/repub.svg";
import riso from "../images/riso-logo.svg";
import scenicRoute from "../images/scenic-route.svg";

export const metadata: Metadata = {
title: "hafa.io",
Expand All @@ -30,7 +31,7 @@ function FooterIcon({
return (
<ExternalAnchor
href={href}
className="p-1 hover:text-black dark:hover:text-gray-100"
className="p-1 hover:text-teal-600 dark:hover:text-teal-400"
>
{icon}
</ExternalAnchor>
Expand All @@ -39,9 +40,9 @@ function FooterIcon({

export default function Hero(): ReactElement {
return (
<div className="dark:bg-gray-800">
<div className="fixed w-full shadow-sm bg-white/80 backdrop-blur-sm backdrop-saturate-150 transition-opacity duration-500 opacity-0 scroll-show dark:bg-gray-800/80 dark:backdrop-brightness-150">
<div className="max-w-4xl h-full mx-auto my-2 px-6 flex items-center justify-between dark:text-gray-100">
<div className="bg-zinc-50 dark:bg-zinc-900">
<div className="fixed z-50 w-full shadow-sm bg-white/80 backdrop-blur-sm backdrop-saturate-150 transition-opacity duration-500 opacity-0 scroll-show dark:bg-zinc-800/80 dark:backdrop-brightness-150">
<div className="max-w-4xl h-full mx-auto my-2 px-6 flex items-center justify-between dark:text-zinc-100">
<Link href="/">
<span className="flex items-center">
<Image
Expand All @@ -56,20 +57,30 @@ export default function Hero(): ReactElement {
<ThemeButton />
</div>
</div>
<div
className={`h-screen w-full bg-center bg-cover flex justify-center items-center`}
style={{ backgroundImage: `url(${splash.src})` }}
>
<span className="text-8xl font-bold text-white transition-opacity duration-500 scroll-hide font-cursive select-none">
<div className="relative h-screen w-full flex justify-center items-center overflow-hidden">
<Image
src={splash}
alt=""
fill
priority
sizes="100vw"
className="hero-zoom object-cover object-center"
/>
<div className="absolute inset-0 bg-linear-to-t from-black/40 to-transparent" />
<span className="relative text-8xl font-bold text-white transition-opacity duration-500 scroll-hide font-cursive select-none">
hafa.io
</span>
</div>
<div className="min-h-screen max-w-4xl mx-auto flex flex-col items-center">
<h2 className="text-4xl font-bold py-4 mt-4 bg-clip-text text-transparent bg-linear-to-br from-teal-400 to-teal-500">
Projects
</h2>
<ul className="px-4 space-y-8 w-full">
<div className="min-h-screen max-w-4xl mx-auto flex flex-col items-center pb-32">
<div className="reveal flex flex-col items-center gap-3 py-8 mt-4">
<h2 className="text-4xl font-bold tracking-tight text-zinc-900 dark:text-zinc-100">
Projects
</h2>
<span className="h-1 w-16 rounded-full bg-linear-to-r from-teal-400 to-teal-500" />
</div>
<ul className="px-4 w-full columns-1 md:columns-2 lg:columns-3 gap-6">
<Project
tint="from-white to-sky-50 dark:from-zinc-800 dark:to-sky-950/30"
logo={
<Image
src={(repub as Svg).src}
Expand All @@ -86,7 +97,7 @@ export default function Hero(): ReactElement {
customization and allows you to include images.`}
buttons={[
{
text: "Chrome Store",
text: "Chrome",
href: "https://chrome.google.com/webstore/detail/repub/blkjpagbjaekkpojgcgdapmikoaolpbl",
icon: <FaChrome />,
},
Expand All @@ -98,6 +109,32 @@ export default function Hero(): ReactElement {
]}
/>
<Project
tint="from-white to-indigo-50 dark:from-zinc-800 dark:to-indigo-950/30"
logo={
<Image
src={(riso as Svg).src}
alt="Risograph logo"
height={72}
width={72}
/>
}
name="Spot Color Separation"
description="Website for separating an image into spot colors. Intended for decomposing images for a Risograph."
buttons={[
{
text: "Website",
href: "https://hafaio.github.io/color-separation",
icon: <FaGlobe />,
},
{
text: "Github",
href: "https://github.com/hafaio/color-separation",
icon: <FaGithub />,
},
]}
/>
<Project
tint="from-white to-blue-50 dark:from-zinc-800 dark:to-blue-950/30"
logo={<span className="text-6xl">🐀</span>}
name="Loose RAT Helper"
description="Helper for finding 'loose' (homophone) Remote Associates Tests given a starting word."
Expand All @@ -115,6 +152,7 @@ export default function Hero(): ReactElement {
]}
/>
<Project
tint="from-white to-violet-50 dark:from-zinc-800 dark:to-violet-950/30"
logo={
<Image
src={(asciiMath as Svg).src}
Expand All @@ -127,7 +165,7 @@ export default function Hero(): ReactElement {
description="Ascii math unicode is an open source chrome extension for converting highlighted ascii math into unicode math expressions."
buttons={[
{
text: "Chrome Store",
text: "Chrome",
href: "https://chrome.google.com/webstore/detail/ascii-math-unicode/llehdcbaonklonjlfgeggamnebgggoab",
icon: <FaChrome />,
},
Expand All @@ -139,31 +177,50 @@ export default function Hero(): ReactElement {
]}
/>
<Project
tint="from-white to-cyan-50 dark:from-zinc-800 dark:to-cyan-950/30"
logo={
<Image
src={(riso as Svg).src}
alt="Risograph logo"
src={(scenicRoute as Svg).src}
alt="Scenic Route logo"
height={72}
width={72}
/>
}
name="Spot Color Separation"
description="Website for separating an image into spot colors. Intended for decomposing images for a Risograph."
name="Scenic Route"
description="Navigation for taking the scenic route."
buttons={[
{
text: "Website",
href: "https://hafaio.github.io/color-separation",
href: "https://hafaio.github.io/scenic-route",
icon: <FaGlobe />,
},
{
text: "Github",
href: "https://github.com/hafaio/color-separation",
href: "https://github.com/hafaio/scenic-route",
icon: <FaGithub />,
},
]}
/>
<Project
tint="from-white to-purple-50 dark:from-zinc-800 dark:to-purple-950/30"
logo={<span className="text-6xl">🎹</span>}
name="Synesthizer"
description="A synesthetic synthesizer that converts images into piano compositions."
buttons={[
{
text: "Website",
href: "https://hafaio.github.io/synesthizer",
icon: <FaGlobe />,
},
{
text: "Github",
href: "https://github.com/hafaio/synesthizer",
icon: <FaGithub />,
},
]}
/>
</ul>
<div className="my-8 space-y-2 w-full text-gray-600 dark:text-gray-400">
<div className="my-8 space-y-2 w-full text-zinc-600 dark:text-zinc-400">
<div className="text-md flex justify-center">
<FooterIcon href="https://github.com/hafaio" icon={<FaGithub />} />
</div>
Expand Down
18 changes: 10 additions & 8 deletions components/project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function Button({ text, href, icon }: ButtonProps): ReactElement {
<ExternalAnchor href={href} className="grow md:grow-0">
<button
type="button"
className="w-full text-gray-600 rounded-lg px-4 py-2 border transition hover:text-black hover:shadow-sm active:shadow-none space-x-2 flex justify-center items-center dark:text-gray-400 dark:hover:text-gray-100 dark:border-gray-400 dark:hover:border-gray-100 dark:hover:shadow-none focus:ring-3 ring-teal-400"
className="w-full rounded-lg px-4 py-2 transition-colors bg-zinc-100 text-zinc-700 hover:bg-teal-50 hover:text-teal-700 space-x-2 flex justify-center items-center dark:bg-zinc-700/60 dark:text-zinc-300 dark:hover:bg-teal-950/50 dark:hover:text-teal-300 focus:ring-3 ring-teal-400"
>
<span>{text}</span>
{icon}
Expand All @@ -26,25 +26,27 @@ export default function Project({
name,
description,
buttons,
tint = "from-white to-zinc-100 dark:from-zinc-800 dark:to-zinc-700/40",
}: {
logo?: React.ReactElement;
name: string;
description: string;
buttons: ButtonProps[];
tint?: string;
}): ReactElement {
// {logo && <StaticImage src={logo} alt={name} height={72} width={72} />}

return (
<li className="rounded-lg shadow-sm overflow-hidden bg-gray-100 md:flex dark:bg-gray-700 dark:shadow-none">
<div className="bg-gray-300 h-40 flex shrink-0 justify-center items-center md:h-auto md:w-48">
<li className="reveal mb-6 break-inside-avoid flex flex-col rounded-xl overflow-hidden bg-white ring-1 ring-zinc-200 shadow-sm transition-shadow hover:shadow-md hover:ring-2 hover:ring-teal-400/50 dark:bg-zinc-800 dark:ring-zinc-700/50 dark:shadow-none">
<div
className={`bg-linear-to-br ${tint} h-40 flex shrink-0 justify-center items-center`}
>
{logo ?? null}
</div>
<div className="space-y-4 p-4">
<div className="flex flex-col gap-4 p-4">
{/* eslint-disable-next-line spellcheck/spell-checker */}
<h3 className="text-2xl font-semibold text-center md:text-left dark:text-gray-100">
<h3 className="text-2xl font-semibold text-center md:text-left dark:text-zinc-100">
{name}
</h3>
<p className="text-gray-600 dark:text-gray-400">{description}</p>
<p className="text-zinc-600 dark:text-zinc-400">{description}</p>
<div className="flex space-x-4">
{buttons.map((props) => (
<Button {...props} key={props.text} />
Expand Down
2 changes: 1 addition & 1 deletion components/theme-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function ThemeButton(): ReactElement {
type="button"
onClick={toggleTheme}
title={themeTitle}
className="p-2 rounded-full ring-teal-400 text-gray-500 hover:bg-gray-300 focus:ring-3 dark:text-gray-400 dark:hover:bg-gray-700"
className="p-2 rounded-full ring-teal-400 text-zinc-500 hover:bg-zinc-300 focus:ring-3 dark:text-zinc-400 dark:hover:bg-zinc-700"
>
{themeIcon}
</button>
Expand Down
Loading
Loading