mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-07-16 18:55:30 -04:00
remove react-spring dependency
This commit is contained in:
@@ -14,9 +14,6 @@
|
||||
background-color: var(--colors-codeBackground);
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-radius: var(--radii-corner);
|
||||
transition:
|
||||
background var(--transitions-fade),
|
||||
border var(--transitions-fade);
|
||||
}
|
||||
|
||||
.codeBlock :global(.line-number)::before {
|
||||
@@ -99,7 +96,4 @@
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-top-right-radius: var(--radii-corner);
|
||||
border-bottom-left-radius: var(--radii-corner);
|
||||
transition:
|
||||
background var(--transitions-fade),
|
||||
border var(--transitions-fade);
|
||||
}
|
||||
|
@@ -5,7 +5,4 @@
|
||||
background-color: var(--colors-codeBackground);
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-radius: var(--radii-corner);
|
||||
transition:
|
||||
background var(--transitions-fade),
|
||||
border var(--transitions-fade);
|
||||
}
|
||||
|
@@ -5,9 +5,6 @@
|
||||
border-top: 1px solid var(--colors-kindaLight);
|
||||
background-color: var(--colors-backgroundOuter);
|
||||
color: var(--colors-mediumDark);
|
||||
transition:
|
||||
background var(--transitions-fade),
|
||||
border var(--transitions-fade);
|
||||
}
|
||||
|
||||
.row {
|
||||
@@ -50,34 +47,28 @@
|
||||
.heart {
|
||||
display: inline-block;
|
||||
color: var(--colors-error);
|
||||
animation: pulse 10s ease 7.5s infinite;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.heart {
|
||||
animation: pulse 10s ease 7.5s infinite;
|
||||
will-change: transform;
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
2% {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
4% {
|
||||
transform: scale(1);
|
||||
}
|
||||
6% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
8% {
|
||||
transform: scale(1);
|
||||
}
|
||||
/* pause for ~9 out of 10 seconds */
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
2% {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
4% {
|
||||
transform: scale(1);
|
||||
}
|
||||
6% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
8% {
|
||||
transform: scale(1);
|
||||
}
|
||||
/* pause for ~9 out of 10 seconds */
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,9 +4,6 @@
|
||||
padding: 0.7em 1.5em;
|
||||
border-bottom: 1px solid var(--colors-kindaLight);
|
||||
background-color: var(--colors-backgroundHeader);
|
||||
transition:
|
||||
background var(--transitions-fade),
|
||||
border var(--transitions-fade);
|
||||
|
||||
/* make sticky */
|
||||
position: sticky;
|
||||
|
@@ -20,9 +20,3 @@
|
||||
background: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.link {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useId } from "react";
|
||||
import { animated, Globals, useSpring, useReducedMotion } from "@react-spring/web";
|
||||
import { useFirstMountState, useHasMounted, useTheme } from "../../hooks";
|
||||
import { useHasMounted, useTheme } from "../../hooks";
|
||||
import { FiSun, FiMoon } from "react-icons/fi";
|
||||
import { BsThreeDots } from "react-icons/bs";
|
||||
|
||||
import styles from "./ThemeToggle.module.css";
|
||||
|
||||
@@ -13,140 +13,24 @@ export type ThemeToggleProps = {
|
||||
const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
const hasMounted = useHasMounted();
|
||||
const { theme, setTheme } = useTheme();
|
||||
const isFirstMount = useFirstMountState();
|
||||
const prefersReducedMotion = useReducedMotion() ?? false;
|
||||
const maskId = useId(); // SSR-safe ID to cross-reference areas of the SVG
|
||||
|
||||
// default to light since `theme` might be undefined
|
||||
const safeTheme = theme === "dark" ? theme : "light";
|
||||
|
||||
// accessibility: disable animation if user prefers reduced motion
|
||||
useEffect(() => {
|
||||
Globals.assign({
|
||||
skipAnimation: isFirstMount || prefersReducedMotion,
|
||||
});
|
||||
}, [isFirstMount, prefersReducedMotion]);
|
||||
|
||||
// modified from https://jfelix.info/blog/using-react-spring-to-animate-svg-icons-dark-mode-toggle
|
||||
const springProperties = {
|
||||
light: {
|
||||
svg: {
|
||||
transform: "rotate(90deg)",
|
||||
},
|
||||
circle: {
|
||||
r: 5,
|
||||
},
|
||||
mask: {
|
||||
cx: "100%",
|
||||
cy: "0%",
|
||||
},
|
||||
lines: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
svg: {
|
||||
transform: "rotate(40deg)",
|
||||
},
|
||||
circle: {
|
||||
r: 9,
|
||||
},
|
||||
mask: {
|
||||
cx: "50%",
|
||||
cy: "23%",
|
||||
},
|
||||
lines: {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
springConfig: { mass: 4, tension: 250, friction: 35 },
|
||||
};
|
||||
|
||||
const { svg, circle, mask, lines } = springProperties[safeTheme];
|
||||
|
||||
const svgContainerProps = useSpring({
|
||||
...svg,
|
||||
config: springProperties.springConfig,
|
||||
});
|
||||
const centerCircleProps = useSpring({
|
||||
...circle,
|
||||
config: springProperties.springConfig,
|
||||
});
|
||||
const maskedCircleProps = useSpring({
|
||||
...mask,
|
||||
config: springProperties.springConfig,
|
||||
});
|
||||
const linesProps = useSpring({
|
||||
...lines,
|
||||
config: springProperties.springConfig,
|
||||
});
|
||||
|
||||
// render a blank div of the same size to avoid layout shifting until we're fully mounted and self-aware
|
||||
// render a placeholder icon to avoid layout shifting until we're fully mounted and self-aware
|
||||
if (!hasMounted) {
|
||||
return (
|
||||
<div className={styles.toggle}>
|
||||
<div className={className} />
|
||||
<BsThreeDots className={className} style={{ fill: "var(--colors-mediumLight)" }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => setTheme(safeTheme === "light" ? "dark" : "light")}
|
||||
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
||||
className={styles.toggle}
|
||||
title={safeTheme === "light" ? "Toggle Dark Mode" : "Toggle Light Mode"}
|
||||
aria-label={safeTheme === "light" ? "Toggle Dark Mode" : "Toggle Light Mode"}
|
||||
title={theme === "light" ? "Toggle Dark Mode" : "Toggle Light Mode"}
|
||||
aria-label={theme === "light" ? "Toggle Dark Mode" : "Toggle Light Mode"}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<animated.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
style={{
|
||||
...svgContainerProps,
|
||||
}}
|
||||
className={className}
|
||||
aria-hidden
|
||||
>
|
||||
<mask id={`mask-${maskId}`}>
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="white" />
|
||||
<animated.circle
|
||||
r="9"
|
||||
fill="black"
|
||||
// @ts-ignore
|
||||
style={maskedCircleProps}
|
||||
/>
|
||||
</mask>
|
||||
|
||||
{/* circle shared by both the sun and crescent moon */}
|
||||
<animated.circle
|
||||
cx="12"
|
||||
cy="12"
|
||||
fill="currentColor"
|
||||
mask={`url(#mask-${maskId})`}
|
||||
// @ts-ignore
|
||||
style={centerCircleProps}
|
||||
/>
|
||||
|
||||
{/* sunrays pulled from https://github.com/feathericons/feather/blob/734f3f51144e383cfdc6d0916831be8d1ad2a749/icons/sun.svg?short_path=fea872c#L13 */}
|
||||
{/* @ts-ignore */}
|
||||
<animated.g stroke="currentColor" style={linesProps}>
|
||||
<line x1="12" y1="1" x2="12" y2="3" />
|
||||
<line x1="12" y1="21" x2="12" y2="23" />
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
||||
<line x1="1" y1="12" x2="3" y2="12" />
|
||||
<line x1="21" y1="12" x2="23" y2="12" />
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||
</animated.g>
|
||||
</animated.svg>
|
||||
{theme === "light" ? <FiSun className={className} /> : <FiMoon className={className} />}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user