style(hero buttons): improve micro interactions of buttons with transitions

This commit is contained in:
alexsparkes
2024-12-16 18:19:22 +00:00
parent 4fe3df2a80
commit 7e8ad29cbc
3 changed files with 95 additions and 20 deletions

View File

@@ -1,10 +1,11 @@
import variables from 'config/variables';
import { useState, useEffect } from 'react';
import { useState, useEffect, useMemo } from 'react';
import EventBus from 'utils/eventbus';
import { Button } from 'components/Elements';
import { MdFlag, MdOutlineVisibilityOff, MdOutlineVisibility } from 'react-icons/md';
import Slider from '../../../Form/Settings/Slider/Slider';
import values from 'utils/data/slider_values.json';
import { motion, AnimatePresence } from 'framer-motion';
const Preview = (props) => {
return (
@@ -19,6 +20,62 @@ const Preview = (props) => {
);
};
const VisibilityToggleButton = ({ setting, onClick }) => {
const iconVariants = {
initial: { opacity: 0, scale: 0.8 },
animate: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.8 },
};
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
return (
<button
type="button"
className="bg-modal-content-light hover:bg-[#e5e5e5] active:bg-[#d5d5d5]
dark:bg-modal-content-dark dark:hover:bg-[#565656] dark:active:bg-[#464646]
p-10 rounded flex flex-col gap-2
transition-all ease-in-out duration-700
focus:outline-none focus:ring-2 focus:ring-offset-2
focus:ring-blue-600 dark:focus:ring-blue-400
focus:ring-offset-white dark:focus:ring-offset-gray-900"
onClick={onClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onClick();
}
}}
aria-checked={setting}
aria-label={setting ? 'Hide content' : 'Show content'}
role="switch"
>
<AnimatePresence mode="wait" initial={false}>
<motion.span
key={setting ? 'hide' : 'show'}
variants={iconVariants}
initial={prefersReducedMotion ? 'animate' : 'initial'}
animate="animate"
exit={prefersReducedMotion ? 'animate' : 'exit'}
transition={{ duration: prefersReducedMotion ? 0 : 0.2 }}
className="text-2xl text-gray-900 dark:text-gray-100"
aria-hidden="true"
>
{setting ? <MdOutlineVisibilityOff /> : <MdOutlineVisibility />}
</motion.span>
</AnimatePresence>
<motion.span
initial={prefersReducedMotion ? { opacity: 1 } : { opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: prefersReducedMotion ? 0 : 0.2 }}
className="text-base text-gray-900 dark:text-gray-100"
>
{setting ? 'Hide' : 'Show'}
</motion.span>
</button>
);
};
const Controls = (props) => {
const [setting, setSetting] = useState(localStorage.getItem(props.setting) === 'true');
@@ -45,36 +102,45 @@ const Controls = (props) => {
EventBus.emit('refresh', props.category);
};
const VisibilityToggle = () => (
<Button
type="settings"
onClick={changeSetting}
icon={setting ? <MdOutlineVisibilityOff /> : <MdOutlineVisibility />}
label={setting ? 'Hide' : 'Show'}
/>
);
const ReportButton = () => {
return (
<Button
type="settings"
<button
type="button"
className="bg-modal-content-light hover:bg-[#e5e5e5] active:bg-[#d5d5d5]
dark:bg-modal-content-dark dark:hover:bg-[#565656] dark:active:bg-[#464646]
p-10 rounded flex flex-col gap-2
transition-all ease-in-out duration-700
focus:outline-none focus:ring-2 focus:ring-offset-2
focus:ring-blue-600 dark:focus:ring-blue-400
focus:ring-offset-white dark:focus:ring-offset-gray-900"
onClick={() =>
window.open(variables.constants.BUG_REPORT + props.title.split(' ').join('+'), '_blank')
}
icon={<MdFlag />}
label={variables.getMessage('settings:sections.header.report_issue')}
/>
aria-label={`Report an issue with ${props.title}`}
>
<span className="text-2xl" aria-hidden="true">
<MdFlag />
</span>
<span className="text-base capitalize">
{variables.getMessage('settings:sections.header.report_issue')}
</span>
</button>
);
};
const memoizedToggle = useMemo(
() => <VisibilityToggleButton setting={setting} onClick={changeSetting} />,
[setting],
);
return (
<div className="h-full flex flex-col">
<h1 className="py-3 uppercase tracking-tight text-neutral-300">Controls</h1>
<div className="grid grid-cols-2 gap-5 mb-5">
{props.visibilityToggle && memoizedToggle}
{props.report !== false && <ReportButton />}
</div>
<div className="bg-modal-content-light dark:bg-modal-content-dark p-10 rounded flex flex-col gap-10 flex-grow">
<div className="grid grid-cols-2 gap-5">
{props.visibilityToggle && <VisibilityToggle />}
{props.report !== false && <ReportButton />}
</div>
{(props.zoomSetting !== null || props.zoomSetting !== '') && (
<Slider
name={props.zoomSetting}

View File

@@ -213,3 +213,12 @@ body {
.modal-clamp-width {
width: clamp(60vw, 1400px, 90vw);
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}