filling in right bar
This commit is contained in:
BIN
public/resume.pdf
Normal file
BIN
public/resume.pdf
Normal file
Binary file not shown.
47
src/app.css
47
src/app.css
@@ -128,6 +128,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Manual dark mode via .dark class */
|
||||||
|
.dark {
|
||||||
|
--color-rosewater: #efc9c2;
|
||||||
|
--color-flamingo: #ebb2b2;
|
||||||
|
--color-pink: #f2a7de;
|
||||||
|
--color-mauve: #b889f4;
|
||||||
|
--color-red: #ea7183;
|
||||||
|
--color-maroon: #ea838c;
|
||||||
|
--color-peach: #f39967;
|
||||||
|
--color-yellow: #eaca89;
|
||||||
|
--color-green: #96d382;
|
||||||
|
--color-teal: #78cec1;
|
||||||
|
--color-sky: #91d7e3;
|
||||||
|
--color-sapphire: #68bae0;
|
||||||
|
--color-blue: #739df2;
|
||||||
|
--color-lavender: #a0a8f6;
|
||||||
|
--color-text: #b5c1f1;
|
||||||
|
--color-subtext1: #a6b0d8;
|
||||||
|
--color-subtext0: #959ec2;
|
||||||
|
--color-overlay2: #848cad;
|
||||||
|
--color-overlay1: #717997;
|
||||||
|
--color-overlay0: #63677f;
|
||||||
|
--color-surface2: #505469;
|
||||||
|
--color-surface1: #3e4255;
|
||||||
|
--color-surface0: #2c2f40;
|
||||||
|
--color-base: #1e1e2e;
|
||||||
|
--color-mantle: #141620;
|
||||||
|
--color-crust: #0e0f16;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: "Source Code Pro", monospace;
|
font-family: "Source Code Pro", monospace;
|
||||||
}
|
}
|
||||||
@@ -471,3 +501,20 @@ input[type="checkbox"]:checked::before {
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@keyframes shaker {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
transform: rotate(-15deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shaker:hover {
|
||||||
|
animation: shaker 0.5s ease;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import { onMount, createEffect, createSignal, Show, For } from "solid-js";
|
|||||||
import { api } from "~/lib/api";
|
import { api } from "~/lib/api";
|
||||||
import { TerminalSplash } from "./TerminalSplash";
|
import { TerminalSplash } from "./TerminalSplash";
|
||||||
import { insertSoftHyphens } from "~/lib/client-utils";
|
import { insertSoftHyphens } from "~/lib/client-utils";
|
||||||
|
import GitHub from "./icons/GitHub";
|
||||||
|
import LinkedIn from "./icons/LinkedIn";
|
||||||
|
import MoonIcon from "./icons/MoonIcon";
|
||||||
|
import SunIcon from "./icons/SunIcon";
|
||||||
|
|
||||||
export function LeftBar() {
|
export function LeftBar() {
|
||||||
const { setLeftBarSize, leftBarVisible, setLeftBarVisible } = useBars();
|
const { setLeftBarSize, leftBarVisible, setLeftBarVisible } = useBars();
|
||||||
@@ -138,7 +142,7 @@ export function LeftBar() {
|
|||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
ref={ref}
|
ref={ref}
|
||||||
class="border-r-overlay2 fixed z-50 h-full w-min border-r-2 transition-transform duration-500 ease-out md:max-w-[20%]"
|
class="border-r-overlay2 bg-base fixed z-50 h-full w-min border-r-2 transition-transform duration-500 ease-out md:max-w-[20%]"
|
||||||
classList={{
|
classList={{
|
||||||
"-translate-x-full": !leftBarVisible(),
|
"-translate-x-full": !leftBarVisible(),
|
||||||
"translate-x-0": leftBarVisible()
|
"translate-x-0": leftBarVisible()
|
||||||
@@ -182,12 +186,9 @@ export function LeftBar() {
|
|||||||
</h3>
|
</h3>
|
||||||
</Typewriter>
|
</Typewriter>
|
||||||
<div class="text-text flex flex-col px-4 text-xl font-bold">
|
<div class="text-text flex flex-col px-4 text-xl font-bold">
|
||||||
<ul class="gap-4">
|
<div class="flex flex-col py-8">
|
||||||
{/* Recent blog posts */}
|
|
||||||
<li class="mt-2 mb-6">
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<span class="text-lg font-semibold">Recent Posts</span>
|
<span class="text-lg font-semibold">Recent Posts</span>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3 pt-4">
|
||||||
<Show when={recentPosts()} fallback={<TerminalSplash />}>
|
<Show when={recentPosts()} fallback={<TerminalSplash />}>
|
||||||
<For each={recentPosts()}>
|
<For each={recentPosts()}>
|
||||||
{(post) => (
|
{(post) => (
|
||||||
@@ -221,8 +222,6 @@ export function LeftBar() {
|
|||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<Typewriter keepAlive={false} class="absolute bottom-12">
|
<Typewriter keepAlive={false} class="absolute bottom-12">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<ul class="gap-4">
|
<ul class="gap-4">
|
||||||
@@ -260,7 +259,20 @@ export function RightBar() {
|
|||||||
let ref: HTMLDivElement | undefined;
|
let ref: HTMLDivElement | undefined;
|
||||||
let actualWidth = 0;
|
let actualWidth = 0;
|
||||||
|
|
||||||
|
const [isDark, setIsDark] = createSignal(false);
|
||||||
|
|
||||||
onMount(() => {
|
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) {
|
if (ref) {
|
||||||
const updateSize = () => {
|
const updateSize = () => {
|
||||||
actualWidth = ref?.offsetWidth || 0;
|
actualWidth = ref?.offsetWidth || 0;
|
||||||
@@ -289,10 +301,21 @@ export function RightBar() {
|
|||||||
setRightBarSize(rightBarVisible() ? actualWidth : 0);
|
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 (
|
return (
|
||||||
<nav
|
<nav
|
||||||
ref={ref}
|
ref={ref}
|
||||||
class="border-l-overlay2 fixed right-0 z-50 hidden h-full min-h-screen w-fit border-l-2 transition-transform duration-500 ease-out md:block md:max-w-[20%]"
|
class="border-l-overlay2 bg-base fixed right-0 z-50 hidden h-full min-h-screen w-fit border-l-2 transition-transform duration-500 ease-out md:block md:max-w-[20%]"
|
||||||
classList={{
|
classList={{
|
||||||
"translate-x-full": !rightBarVisible(),
|
"translate-x-full": !rightBarVisible(),
|
||||||
"translate-x-0": rightBarVisible()
|
"translate-x-0": rightBarVisible()
|
||||||
@@ -303,23 +326,80 @@ export function RightBar() {
|
|||||||
: "cubic-bezier(0.4, 0, 0.2, 1)" // Smooth when hiding
|
: "cubic-bezier(0.4, 0, 0.2, 1)" // Smooth when hiding
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typewriter keepAlive={false} class="z-50">
|
<Typewriter keepAlive={false} class="z-50 px-4 pt-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">
|
<div class="text-text flex h-screen flex-col justify-between py-6">
|
||||||
Right Navigation
|
<div class="flex flex-col gap-6">
|
||||||
|
<h3 class="text-subtext0 rule-around text-lg font-semibold">
|
||||||
|
Connect
|
||||||
</h3>
|
</h3>
|
||||||
<div class="text-text flex h-screen flex-col justify-between px-4 py-10 text-xl font-bold">
|
<ul 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="#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">
|
<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>
|
<a href="/contact">Contact</a>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</div>
|
</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>
|
</Typewriter>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useNavigate } from "@solidjs/router";
|
import { useNavigate } from "@solidjs/router";
|
||||||
import { createEffect, createSignal, For } from "solid-js";
|
import { createSignal, For, onMount, onCleanup } from "solid-js";
|
||||||
|
|
||||||
export interface ErrorBoundaryFallbackProps {
|
export interface ErrorBoundaryFallbackProps {
|
||||||
error: Error;
|
error: Error;
|
||||||
@@ -21,9 +21,11 @@ export default function ErrorBoundaryFallback(
|
|||||||
}
|
}
|
||||||
const [glitchText, setGlitchText] = createSignal("ERROR");
|
const [glitchText, setGlitchText] = createSignal("ERROR");
|
||||||
|
|
||||||
createEffect(() => {
|
// Log error immediately (safe for SSR)
|
||||||
console.error(props.error);
|
console.error(props.error);
|
||||||
|
|
||||||
|
// Client-only glitch animation
|
||||||
|
onMount(() => {
|
||||||
const glitchChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?~`";
|
const glitchChars = "!@#$%^&*()_+-=[]{}|;':\",./<>?~`";
|
||||||
const originalText = "ERROR";
|
const originalText = "ERROR";
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@ export default function ErrorBoundaryFallback(
|
|||||||
}
|
}
|
||||||
}, 400);
|
}, 400);
|
||||||
|
|
||||||
return () => clearInterval(glitchInterval);
|
onCleanup(() => clearInterval(glitchInterval));
|
||||||
});
|
});
|
||||||
|
|
||||||
const createParticles = () => {
|
const createParticles = () => {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export default function ContactPage() {
|
|||||||
|
|
||||||
const LineageQuestionsDropDown = () => {
|
const LineageQuestionsDropDown = () => {
|
||||||
return (
|
return (
|
||||||
<div class="mx-auto px-4 py-12 md:w-3/4 md:flex-row lg:w-1/2">
|
<div class="w-full py-12">
|
||||||
<RevealDropDown title={"Questions about Life and Lineage?"}>
|
<RevealDropDown title={"Questions about Life and Lineage?"}>
|
||||||
<div>
|
<div>
|
||||||
Feel free to use the form{" "}
|
Feel free to use the form{" "}
|
||||||
@@ -198,7 +198,7 @@ export default function ContactPage() {
|
|||||||
<Meta name="description" content="Contact Me" />
|
<Meta name="description" content="Contact Me" />
|
||||||
|
|
||||||
<div class="flex min-h-screen w-full justify-center">
|
<div class="flex min-h-screen w-full justify-center">
|
||||||
<div class="pt-[20vh]">
|
<div class="w-full max-w-4xl px-4 pt-[20vh]">
|
||||||
<div class="text-center text-3xl tracking-widest dark:text-white">
|
<div class="text-center text-3xl tracking-widest dark:text-white">
|
||||||
Contact
|
Contact
|
||||||
</div>
|
</div>
|
||||||
@@ -210,13 +210,13 @@ export default function ContactPage() {
|
|||||||
<Show when={viewer() === "lineage"}>
|
<Show when={viewer() === "lineage"}>
|
||||||
<LineageQuestionsDropDown />
|
<LineageQuestionsDropDown />
|
||||||
</Show>
|
</Show>
|
||||||
<form onSubmit={sendEmailTrigger} class="min-w-[85vw] px-4">
|
<form onSubmit={sendEmailTrigger} class="w-full">
|
||||||
<div
|
<div
|
||||||
class={`flex w-full flex-col justify-evenly pt-6 ${
|
class={`flex w-full flex-col justify-evenly pt-6 ${
|
||||||
viewer() !== "lineage" ? "md:mt-24" : ""
|
viewer() !== "lineage" ? "md:mt-24" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div class="mx-auto w-full justify-evenly md:flex md:w-3/4 md:flex-row lg:w-1/2">
|
<div class="mx-auto w-full justify-evenly md:flex md:flex-row">
|
||||||
<div class="input-group md:mx-4">
|
<div class="input-group md:mx-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -242,7 +242,7 @@ export default function ContactPage() {
|
|||||||
<label class="underlinedInputLabel">Email</label>
|
<label class="underlinedInputLabel">Email</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto w-full pt-6 md:w-3/4 md:pt-12 lg:w-1/2">
|
<div class="mx-auto w-full pt-6 md:pt-12">
|
||||||
<div class="textarea-group">
|
<div class="textarea-group">
|
||||||
<textarea
|
<textarea
|
||||||
required
|
required
|
||||||
@@ -255,7 +255,7 @@ export default function ContactPage() {
|
|||||||
<label class="underlinedInputLabel">Message</label>
|
<label class="underlinedInputLabel">Message</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto flex w-full justify-end pt-4 md:w-3/4 lg:w-1/2">
|
<div class="mx-auto flex w-full justify-end pt-4">
|
||||||
<Show
|
<Show
|
||||||
when={countDown() > 0}
|
when={countDown() > 0}
|
||||||
fallback={
|
fallback={
|
||||||
|
|||||||
16
src/routes/resume.tsx
Normal file
16
src/routes/resume.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Title } from "@solidjs/meta";
|
||||||
|
|
||||||
|
export default function Resume() {
|
||||||
|
return (
|
||||||
|
<main class="flex h-screen w-full flex-col">
|
||||||
|
<Title>Resume - Freno.dev</Title>
|
||||||
|
<div class="flex h-full w-full items-center justify-center">
|
||||||
|
<iframe
|
||||||
|
src="/resume.pdf"
|
||||||
|
class="h-full w-full border-0"
|
||||||
|
title="Resume PDF"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user