mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 11:44:40 +00:00
simplify store theming
This commit is contained in:
@@ -1,154 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { cn } from "../../utils/cn";
|
|
||||||
import React, {
|
|
||||||
createContext,
|
|
||||||
useState,
|
|
||||||
useContext,
|
|
||||||
useRef,
|
|
||||||
useEffect,
|
|
||||||
} from "react";
|
|
||||||
|
|
||||||
const MouseEnterContext = createContext<
|
|
||||||
[boolean, React.Dispatch<React.SetStateAction<boolean>>] | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
export const CardContainer = ({
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
containerClassName,
|
|
||||||
}: {
|
|
||||||
children?: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
containerClassName?: string;
|
|
||||||
}) => {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const [isMouseEntered, setIsMouseEntered] = useState(false);
|
|
||||||
|
|
||||||
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
||||||
if (!containerRef.current) return;
|
|
||||||
const { left, top, width, height } =
|
|
||||||
containerRef.current.getBoundingClientRect();
|
|
||||||
const x = (e.clientX - left - width / 2) / 25;
|
|
||||||
const y = (e.clientY - top - height / 2) / 25;
|
|
||||||
containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseEnter = (_: React.MouseEvent<HTMLDivElement>) => {
|
|
||||||
setIsMouseEntered(true);
|
|
||||||
if (!containerRef.current) return;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseLeave = (_: React.MouseEvent<HTMLDivElement>) => {
|
|
||||||
if (!containerRef.current) return;
|
|
||||||
setIsMouseEntered(false);
|
|
||||||
containerRef.current.style.transform = `rotateY(0deg) rotateX(0deg)`;
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<MouseEnterContext.Provider value={[isMouseEntered, setIsMouseEntered]}>
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex items-center justify-center",
|
|
||||||
containerClassName
|
|
||||||
)}
|
|
||||||
style={{
|
|
||||||
perspective: "1000px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
ref={containerRef}
|
|
||||||
onMouseEnter={handleMouseEnter}
|
|
||||||
onMouseMove={handleMouseMove}
|
|
||||||
onMouseLeave={handleMouseLeave}
|
|
||||||
className={cn(
|
|
||||||
"flex items-center justify-center relative transition-all duration-200 ease-linear",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
style={{
|
|
||||||
transformStyle: "preserve-3d",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</MouseEnterContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CardBody = ({
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"h-96 w-96 [transform-style:preserve-3d] [&>*]:[transform-style:preserve-3d]",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CardItem = ({
|
|
||||||
as: Tag = "div",
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
translateX = 0,
|
|
||||||
translateY = 0,
|
|
||||||
translateZ = 0,
|
|
||||||
rotateX = 0,
|
|
||||||
rotateY = 0,
|
|
||||||
rotateZ = 0,
|
|
||||||
...rest
|
|
||||||
}: {
|
|
||||||
as?: React.ElementType;
|
|
||||||
children: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
translateX?: number | string;
|
|
||||||
translateY?: number | string;
|
|
||||||
translateZ?: number | string;
|
|
||||||
rotateX?: number | string;
|
|
||||||
rotateY?: number | string;
|
|
||||||
rotateZ?: number | string;
|
|
||||||
[key: string]: any;
|
|
||||||
}) => {
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
|
||||||
const [isMouseEntered] = useMouseEnter();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleAnimations();
|
|
||||||
}, [isMouseEntered]);
|
|
||||||
|
|
||||||
const handleAnimations = () => {
|
|
||||||
if (!ref.current) return;
|
|
||||||
if (isMouseEntered) {
|
|
||||||
ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`;
|
|
||||||
} else {
|
|
||||||
ref.current.style.transform = `translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tag
|
|
||||||
ref={ref}
|
|
||||||
className={cn("w-fit transition duration-200 ease-linear", className)}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a hook to use the context
|
|
||||||
export const useMouseEnter = () => {
|
|
||||||
const context = useContext(MouseEnterContext);
|
|
||||||
if (context === undefined) {
|
|
||||||
throw new Error("useMouseEnter must be used within a MouseEnterProvider");
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,7 @@ import logo from '../../../resources/icons/betterseqta-dark-full.png';
|
|||||||
import logoDark from '../../../resources/icons/betterseqta-light-full.png';
|
import logoDark from '../../../resources/icons/betterseqta-light-full.png';
|
||||||
|
|
||||||
export default function header({ searchTerm, setSearchTerm }: { searchTerm: string, setSearchTerm: (value: string) => void }) {
|
export default function header({ searchTerm, setSearchTerm }: { searchTerm: string, setSearchTerm: (value: string) => void }) {
|
||||||
return <header className="sticky top-0 z-50 w-full bg-white border-b shadow-md border-b-white/10 dark:bg-zinc-800">
|
return <header className="sticky top-0 z-50 w-full bg-white border-b shadow-md border-b-white/10 dark:bg-zinc-800/90 backdrop-blur-xl">
|
||||||
<div className="flex items-center justify-between px-4 py-1">
|
<div className="flex items-center justify-between px-4 py-1">
|
||||||
<img src={logo} className="h-16 dark:hidden" />
|
<img src={logo} className="h-16 dark:hidden" />
|
||||||
<img src={logoDark} className="hidden h-16 dark:block" />
|
<img src={logoDark} className="hidden h-16 dark:block" />
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||||
import { CardBody, CardContainer, CardItem } from '../components/store/card';
|
|
||||||
import { Autoplay } from 'swiper/modules';
|
import { Autoplay } from 'swiper/modules';
|
||||||
import Header from '../components/store/header';
|
import Header from '../components/store/header';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
@@ -96,18 +95,20 @@ const Store = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-8 py-4 mx-auto md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid grid-cols-1 gap-4 py-12 mx-auto sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{filteredThemes.map((theme, index) => (
|
{filteredThemes.map((theme, index) => (
|
||||||
<div key={index} className='w-full cursor-pointer'>
|
<div key={index} className='w-full cursor-pointer'>
|
||||||
<div className="bg-gray-50 w-full transition-all duration-300 relative group/card dark:hover:shadow-2xl dark:hover:shadow-emerald-500/[0.1] dark:bg-black dark:border-white/[0.2] border-black/[0.1] h-auto rounded-xl p-6 border">
|
<div className="bg-gray-50 w-full transition-all duration-300 relative group/card flex flex-col dark:hover:shadow-2xl dark:hover:shadow-white/[0.1] dark:bg-zinc-800 dark:border-white/[0.1] h-auto rounded-xl p-6 border">
|
||||||
<div
|
<div>
|
||||||
className="mb-1 text-xl font-bold text-neutral-600 dark:text-white">
|
|
||||||
|
<div className="mb-1 text-xl font-bold text-neutral-600 dark:text-white">
|
||||||
{theme.name}
|
{theme.name}
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p className="max-w-sm mb-4 text-sm text-neutral-500 dark:text-neutral-300">
|
||||||
className="max-w-sm mb-4 text-sm text-neutral-500 dark:text-neutral-300">
|
|
||||||
{theme.description}
|
{theme.description}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className='w-full'>
|
className='w-full'>
|
||||||
<img src={theme.image} alt="Theme Preview" className="object-cover w-full h-48 rounded-md" />
|
<img src={theme.image} alt="Theme Preview" className="object-cover w-full h-48 rounded-md" />
|
||||||
|
|||||||
Reference in New Issue
Block a user