mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2026-06-13 19:55:26 -04:00
Migrate to app router (#2254)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
.toggle {
|
||||
border: 0;
|
||||
padding: 0.6em;
|
||||
margin-right: -0.6em;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--colors-mediumDark);
|
||||
}
|
||||
|
||||
.toggle:hover,
|
||||
.toggle:focus-visible {
|
||||
color: var(--colors-warning);
|
||||
}
|
||||
@@ -1,23 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useId } from "react";
|
||||
import { useSpring, animated, Globals } from "@react-spring/web";
|
||||
import useMedia from "../../hooks/useMedia";
|
||||
import { animated, Globals, useSpring, useReducedMotion } from "@react-spring/web";
|
||||
import useFirstMountState from "../../hooks/useFirstMountState";
|
||||
import useTheme from "../../hooks/useTheme";
|
||||
import useHasMounted from "../../hooks/useHasMounted";
|
||||
import { styled, theme } from "../../lib/styles/stitches.config";
|
||||
|
||||
const Button = styled("button", {
|
||||
border: 0,
|
||||
padding: "0.6em",
|
||||
marginRight: "-0.6em",
|
||||
background: "none",
|
||||
cursor: "pointer",
|
||||
color: theme.colors.mediumDark,
|
||||
|
||||
"&:hover, &:focus-visible": {
|
||||
color: theme.colors.warning,
|
||||
},
|
||||
});
|
||||
import styles from "./ThemeToggle.module.css";
|
||||
|
||||
export type ThemeToggleProps = {
|
||||
className?: string;
|
||||
@@ -27,7 +16,7 @@ const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
const hasMounted = useHasMounted();
|
||||
const { activeTheme, setTheme } = useTheme();
|
||||
const isFirstMount = useFirstMountState();
|
||||
const prefersReducedMotion = useMedia("(prefers-reduced-motion: reduce)", false);
|
||||
const prefersReducedMotion = useReducedMotion() ?? false;
|
||||
const maskId = useId(); // SSR-safe ID to cross-reference areas of the SVG
|
||||
|
||||
// default to light since `activeTheme` might be undefined
|
||||
@@ -36,7 +25,7 @@ const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
// accessibility: disable animation if user prefers reduced motion
|
||||
useEffect(() => {
|
||||
Globals.assign({
|
||||
skipAnimation: !!isFirstMount || !!prefersReducedMotion,
|
||||
skipAnimation: isFirstMount || prefersReducedMotion,
|
||||
});
|
||||
}, [isFirstMount, prefersReducedMotion]);
|
||||
|
||||
@@ -97,18 +86,20 @@ const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
// render a blank div of the same size to avoid layout shifting until we're fully mounted and self-aware
|
||||
if (!hasMounted) {
|
||||
return (
|
||||
<Button as="div">
|
||||
<div className={styles.toggle}>
|
||||
<div className={className} />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
<button
|
||||
onClick={() => setTheme(safeTheme === "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"}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<animated.svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
@@ -146,6 +137,7 @@ const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
/>
|
||||
|
||||
{/* 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" />
|
||||
@@ -157,7 +149,7 @@ const ThemeToggle = ({ className }: ThemeToggleProps) => {
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||
</animated.g>
|
||||
</animated.svg>
|
||||
</Button>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user