better color handling

This commit is contained in:
Michael Freno
2025-12-18 22:09:17 -05:00
parent 1a77cc08cf
commit bb11775d82
4 changed files with 225 additions and 205 deletions

View File

@@ -9,6 +9,124 @@ import LinkedIn from "./icons/LinkedIn";
import MoonIcon from "./icons/MoonIcon";
import SunIcon from "./icons/SunIcon";
export function RightBarContent() {
const [isDark, setIsDark] = createSignal(false);
onMount(() => {
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (prefersDark) {
setIsDark(true);
document.documentElement.classList.add("dark");
document.documentElement.classList.remove("light");
} else {
setIsDark(false);
document.documentElement.classList.add("light");
document.documentElement.classList.remove("dark");
}
});
const toggleDarkMode = () => {
const newDarkMode = !isDark();
setIsDark(newDarkMode);
if (newDarkMode) {
document.documentElement.classList.add("dark");
document.documentElement.classList.remove("light");
} else {
document.documentElement.classList.add("light");
document.documentElement.classList.remove("dark");
}
};
return (
<div class="text-text flex h-full flex-col justify-between py-6">
<Typewriter keepAlive={false} class="z-50 px-4 pt-4">
<div class="flex flex-col gap-6">
<h3 class="text-subtext0 rule-around text-lg font-semibold">
Connect
</h3>
<ul class="flex flex-col gap-4">
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/contact">Contact Me</a>
</li>
<li>
<a
href="https://github.com/MikeFreno/"
target="_blank"
rel="noreferrer"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<GitHub height={24} width={24} fill={undefined} />
</span>
<span>GitHub</span>
</a>
</li>
<li>
<a
href="https://www.linkedin.com/in/michael-freno-176001256/"
target="_blank"
rel="noreferrer"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<LinkedIn height={24} width={24} fill={undefined} />
</span>
<span>LinkedIn</span>
</a>
</li>
<li>
<a
href="/resume"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<svg
xmlns="http://www.w3.org/2000/svg"
height={24}
width={24}
viewBox="0 0 384 512"
class="fill-text"
>
<path d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zM112 256H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z" />
</svg>
</span>
<span>Resume</span>
</a>
</li>
</ul>
</div>
</Typewriter>
{/* Dark Mode Toggle */}
<div class="border-overlay0 border-t px-4 pt-6">
<button
onClick={toggleDarkMode}
class="hover:bg-surface0 flex w-full items-center gap-3 rounded-lg p-3 transition-all duration-200 ease-in-out hover:scale-105"
aria-label="Toggle dark mode"
>
<Show
when={isDark()}
fallback={<SunIcon size={24} fill="var(--color-text)" />}
>
<MoonIcon size={24} fill="var(--color-text)" />
</Show>
<span class="font-semibold">
<Show
when={isDark()}
fallback={<Typewriter keepAlive={false}>Light Mode</Typewriter>}
>
<Typewriter keepAlive={false}>Dark Mode</Typewriter>
</Show>
</span>
</button>
</div>
</div>
);
}
export function LeftBar() {
const { setLeftBarSize, leftBarVisible, setLeftBarVisible } = useBars();
let ref: HTMLDivElement | undefined;
@@ -156,7 +274,7 @@ export function LeftBar() {
{/* Hamburger menu button - positioned at right edge of navbar */}
<button
onClick={() => setLeftBarVisible(!leftBarVisible())}
class="hamburger-menu-btn bg-surface0 hover:bg-surface1 absolute top-4 -right-14 rounded-md p-2 shadow-md transition-colors"
class="hamburger-menu-btn absolute top-4 -right-14 z-10 rounded-md p-2 shadow-md backdrop-blur-2xl transition-transform duration-600 ease-in-out hover:scale-110"
classList={{
hidden: leftBarVisible()
}}
@@ -180,75 +298,75 @@ export function LeftBar() {
</svg>
</button>
<Typewriter speed={10} keepAlive={10000} class="z-50 pr-8 pl-4">
<h3 class="hover:text-subtext0 w-fit text-center text-3xl underline transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105">
<a href="/">Freno.dev</a>
</h3>
</Typewriter>
<div class="text-text flex flex-col px-4 text-xl font-bold">
<div class="flex flex-col py-8">
<span class="text-lg font-semibold">Recent Posts</span>
<div class="flex flex-col gap-3 pt-4">
<Show when={recentPosts()} fallback={<TerminalSplash />}>
<For each={recentPosts()}>
{(post) => (
<a
href={`/blog/${post.title}`}
class="hover:text-subtext0 block transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105 hover:font-bold"
>
<Typewriter class="flex flex-col" keepAlive={false}>
<div class="relative overflow-hidden">
<img
src={post.banner_photo || "/blueprint.jpg"}
alt="post-cover"
class="float-right mb-1 ml-2 h-12 w-16 rounded object-cover"
/>
<span class="inline wrap-break-word hyphens-auto">
{insertSoftHyphens(post.title.replace(/_/g, " "))}
</span>
</div>
<div class="flex h-full min-h-full flex-col overflow-y-auto">
<Typewriter speed={10} keepAlive={10000} class="z-50 pr-8 pl-4">
<h3 class="hover:text-subtext0 w-fit text-center text-3xl underline transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105">
<a href="/">Freno.dev</a>
</h3>
</Typewriter>
<span class="text-subtext0 clear-both text-sm">
{new Date(post.date).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric"
})}
</span>
</Typewriter>
</a>
)}
</For>
</Show>
<div class="text-text flex flex-1 flex-col px-4 pb-4 text-xl font-bold">
<div class="flex flex-col py-8">
<span class="text-lg font-semibold">Recent Posts</span>
<div class="flex flex-col gap-3 pt-4">
<Show when={recentPosts()} fallback={<TerminalSplash />}>
<For each={recentPosts()}>
{(post) => (
<a
href={`/blog/${post.title}`}
class="hover:text-subtext0 block transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105 hover:font-bold"
>
<Typewriter class="flex flex-col" keepAlive={false}>
<div class="relative overflow-hidden">
<img
src={post.banner_photo || "/blueprint.jpg"}
alt="post-cover"
class="float-right mb-1 ml-2 h-12 w-16 rounded object-cover"
/>
<span class="inline wrap-break-word hyphens-auto">
{insertSoftHyphens(post.title.replace(/_/g, " "))}
</span>
</div>
<span class="text-subtext0 clear-both text-sm">
{new Date(post.date).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric"
})}
</span>
</Typewriter>
</a>
)}
</For>
</Show>
</div>
</div>
{/* Navigation Links */}
<div class="mt-auto">
<Typewriter keepAlive={false}>
<div class="flex flex-col gap-4 py-6">
<ul class="gap-4">
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/">Home</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/blog">Blog</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/login">Login</a>
</li>
</ul>
</div>
</Typewriter>
{/* RightBar content on mobile */}
<div class="border-overlay0 border-t pt-8 md:hidden">
<RightBarContent />
</div>
</div>
</div>
<Typewriter keepAlive={false} class="absolute bottom-12">
<div class="flex flex-col gap-4">
<ul class="gap-4">
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/">Home</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/blog">Blog</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/contact">Contact</a>
</li>
</ul>
{/* Right bar navigation merged for mobile */}
<ul class="border-overlay0 gap-4 border-t pt-4 md:hidden">
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/">Home</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="#about">About</a>
</li>
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/contact">Contact</a>
</li>
</ul>
</div>
</Typewriter>
</div>
</nav>
);
@@ -259,20 +377,7 @@ export function RightBar() {
let ref: HTMLDivElement | undefined;
let actualWidth = 0;
const [isDark, setIsDark] = createSignal(false);
onMount(() => {
// Initialize dark mode based on system preference
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark" || (!savedTheme && prefersDark)) {
setIsDark(true);
document.documentElement.classList.add("dark");
}
if (ref) {
const updateSize = () => {
actualWidth = ref?.offsetWidth || 0;
@@ -282,7 +387,6 @@ export function RightBar() {
updateSize();
const resizeObserver = new ResizeObserver((entries) => {
// Use requestAnimationFrame to avoid ResizeObserver loop error
requestAnimationFrame(() => {
actualWidth = ref?.offsetWidth || 0;
setRightBarSize(rightBarVisible() ? actualWidth : 0);
@@ -296,22 +400,10 @@ export function RightBar() {
}
});
// Update size when visibility changes
createEffect(() => {
setRightBarSize(rightBarVisible() ? actualWidth : 0);
});
const toggleDarkMode = () => {
setIsDark(!isDark());
if (!isDark()) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
}
};
return (
<nav
ref={ref}
@@ -322,85 +414,11 @@ export function RightBar() {
}}
style={{
"transition-timing-function": rightBarVisible()
? "cubic-bezier(0.34, 1.56, 0.64, 1)" // Bounce out when revealing
: "cubic-bezier(0.4, 0, 0.2, 1)" // Smooth when hiding
? "cubic-bezier(0.34, 1.56, 0.64, 1)"
: "cubic-bezier(0.4, 0, 0.2, 1)"
}}
>
<Typewriter keepAlive={false} class="z-50 px-4 pt-4">
<div class="text-text flex h-screen flex-col justify-between py-6">
<div class="flex flex-col gap-6">
<h3 class="text-subtext0 rule-around text-lg font-semibold">
Connect
</h3>
<ul class="flex flex-col gap-4">
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
<a href="/contact">Contact</a>
</li>
<li>
<a
href="https://github.com/MikeFreno/"
target="_blank"
rel="noreferrer"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<GitHub height={24} width={24} fill={undefined} />
</span>
<span>GitHub</span>
</a>
</li>
<li>
<a
href="https://www.linkedin.com/in/michael-freno-176001256/"
target="_blank"
rel="noreferrer"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<LinkedIn height={24} width={24} fill={undefined} />
</span>
<span>LinkedIn</span>
</a>
</li>
<li>
<a
href="/resume"
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
<span class="shaker rounded-full p-2">
<svg
xmlns="http://www.w3.org/2000/svg"
height={24}
width={24}
viewBox="0 0 384 512"
class="fill-text"
>
<path d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zM112 256H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64H272c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z" />
</svg>
</span>
<span>Resume</span>
</a>
</li>
</ul>
</div>
{/* Dark Mode Toggle */}
<div class="border-overlay0 border-t pt-6">
<button
onClick={toggleDarkMode}
class="hover:bg-surface0 flex w-full items-center gap-3 rounded-lg p-3 transition-all duration-200 ease-in-out hover:scale-105"
aria-label="Toggle dark mode"
>
<Show when={isDark()} fallback={<MoonIcon size={24} />}>
<SunIcon size={24} fill="var(--color-text)" />
</Show>
<span class="text-text font-semibold">
{isDark() ? "Light Mode" : "Dark Mode"}
</span>
</button>
</div>
</div>
</Typewriter>
<RightBarContent />
</nav>
);
}