Update src/providers/themeProvider/ThemeProvider.tsx
This commit is contained in:
@@ -1,25 +1,107 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
import type { ThemeConfig, ThemeProviderProps } from "./config/types";
|
||||
import { borderRadiusMap, borderRadiusCappedMap, contentWidthMap, expandedContentWidthMap, baseVwMap, textSizingMap, backgroundComponents, headingFontWeightMap } from "./config/constants";
|
||||
import { cardStyleMap, getGradientBorderedPseudo } from "./styles/cardStyles";
|
||||
import { primaryButtonStyleMap } from "./styles/primaryButtonStyles";
|
||||
import { secondaryButtonStyleMap } from "./styles/secondaryButtonStyles";
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const ThemeContext = createContext<ThemeConfig | undefined>(undefined);
|
||||
interface SocialLink {
|
||||
platform: string;
|
||||
url: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export const useTheme = () => {
|
||||
const context = useContext(ThemeContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useTheme must be used within a ThemeProvider. Wrap your sections in <ThemeProvider> at the app/page level."
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
interface TeamMember {
|
||||
id: string;
|
||||
name: string;
|
||||
role: string;
|
||||
image: string;
|
||||
socialLinks: SocialLink[];
|
||||
}
|
||||
|
||||
export const ThemeProvider = ({
|
||||
interface TeamCardProps {
|
||||
member: TeamMember;
|
||||
}
|
||||
|
||||
function TeamCard({ member }: TeamCardProps) {
|
||||
const [isFlipped, setIsFlipped] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="h-80 w-full cursor-pointer perspective"
|
||||
onMouseEnter={() => setIsFlipped(true)}
|
||||
onMouseLeave={() => setIsFlipped(false)}
|
||||
>
|
||||
<div
|
||||
className="relative w-full h-full transition-transform duration-500 transform-gpu"
|
||||
style={{
|
||||
transformStyle: 'preserve-3d',
|
||||
transform: isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)',
|
||||
}}
|
||||
>
|
||||
{/* Front Side */}
|
||||
<div
|
||||
className="absolute w-full h-full bg-gradient-to-br from-slate-900 to-slate-800 rounded-lg p-6 flex flex-col items-center justify-center border border-slate-700"
|
||||
style={{ backfaceVisibility: 'hidden' }}
|
||||
>
|
||||
<div className="w-24 h-24 rounded-full bg-slate-700 mb-4 overflow-hidden flex items-center justify-center">
|
||||
<img
|
||||
src={member.image}
|
||||
alt={member.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-white text-center">
|
||||
{member.name}
|
||||
</h3>
|
||||
<p className="text-sm text-slate-400 text-center mt-2">
|
||||
{member.role}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Back Side */}
|
||||
<div
|
||||
className="absolute w-full h-full bg-gradient-to-br from-blue-900 to-blue-800 rounded-lg p-6 flex flex-col items-center justify-center border border-blue-700"
|
||||
style={{
|
||||
backfaceVisibility: 'hidden',
|
||||
transform: 'rotateY(180deg)',
|
||||
}}
|
||||
>
|
||||
<h4 className="text-white font-semibold mb-4 text-center">
|
||||
Connect
|
||||
</h4>
|
||||
<div className="flex flex-wrap gap-3 justify-center">
|
||||
{member.socialLinks.map((link) => (
|
||||
<a
|
||||
key={link.platform}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-10 h-10 rounded-full bg-white bg-opacity-20 hover:bg-opacity-30 flex items-center justify-center transition-all duration-300 text-white text-sm font-bold"
|
||||
title={link.platform}
|
||||
>
|
||||
{link.icon}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ThemeProviderProps {
|
||||
children: React.ReactNode;
|
||||
defaultButtonVariant?: string;
|
||||
defaultTextAnimation?: string;
|
||||
borderRadius?: string;
|
||||
contentWidth?: string;
|
||||
sizing?: string;
|
||||
background?: string;
|
||||
cardStyle?: string;
|
||||
primaryButtonStyle?: string;
|
||||
secondaryButtonStyle?: string;
|
||||
headingFontWeight?: string;
|
||||
}
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
defaultButtonVariant,
|
||||
defaultTextAnimation,
|
||||
@@ -31,96 +113,54 @@ export const ThemeProvider = ({
|
||||
primaryButtonStyle,
|
||||
secondaryButtonStyle,
|
||||
headingFontWeight,
|
||||
}: ThemeProviderProps) => {
|
||||
const themeConfig: ThemeConfig = {
|
||||
defaultButtonVariant,
|
||||
defaultTextAnimation,
|
||||
borderRadius,
|
||||
contentWidth,
|
||||
sizing,
|
||||
background,
|
||||
cardStyle,
|
||||
primaryButtonStyle,
|
||||
secondaryButtonStyle,
|
||||
headingFontWeight,
|
||||
}: ThemeProviderProps) {
|
||||
const backgroundClasses = {
|
||||
aurora: 'bg-gradient-to-br from-slate-950 via-purple-900 to-slate-950',
|
||||
light: 'bg-white',
|
||||
dark: 'bg-slate-900',
|
||||
};
|
||||
|
||||
const borderRadiusValue = borderRadiusMap[borderRadius];
|
||||
const borderRadiusCappedValue = borderRadiusCappedMap[borderRadius];
|
||||
const contentWidthValues = contentWidthMap[contentWidth];
|
||||
const expandedContentWidthValues = expandedContentWidthMap[contentWidth];
|
||||
const baseVwValues = baseVwMap[sizing];
|
||||
const textSizingValues = textSizingMap[sizing];
|
||||
const BackgroundComponent = backgroundComponents[background];
|
||||
const headingFontWeightValue = headingFontWeightMap[headingFontWeight];
|
||||
const borderRadiusClasses = {
|
||||
soft: 'rounded-lg',
|
||||
sharp: 'rounded-none',
|
||||
smooth: 'rounded-2xl',
|
||||
};
|
||||
|
||||
const cardStyles = cardStyleMap[cardStyle];
|
||||
const primaryButtonStyles = primaryButtonStyleMap[primaryButtonStyle];
|
||||
const secondaryButtonStyles = secondaryButtonStyleMap[secondaryButtonStyle];
|
||||
const contentWidthClasses = {
|
||||
small: 'max-w-2xl',
|
||||
medium: 'max-w-6xl',
|
||||
large: 'max-w-7xl',
|
||||
};
|
||||
|
||||
const gradientBorderedPseudo = getGradientBorderedPseudo(cardStyle);
|
||||
|
||||
const styleString = `
|
||||
:root {
|
||||
--theme-border-radius: ${borderRadiusValue};
|
||||
--theme-border-radius-capped: ${borderRadiusCappedValue};
|
||||
--width-content-width: ${contentWidthValues.desktop};
|
||||
--width-content-width-expanded: ${expandedContentWidthValues.desktop};
|
||||
--vw: ${baseVwValues.desktop};
|
||||
--heading-font-weight: ${headingFontWeightValue};
|
||||
--text-2xs: ${textSizingValues.desktop.text2xs};
|
||||
--text-xs: ${textSizingValues.desktop.textXs};
|
||||
--text-sm: ${textSizingValues.desktop.textSm};
|
||||
--text-base: ${textSizingValues.desktop.textBase};
|
||||
--text-lg: ${textSizingValues.desktop.textLg};
|
||||
--text-xl: ${textSizingValues.desktop.textXl};
|
||||
--text-2xl: ${textSizingValues.desktop.text2xl};
|
||||
--text-3xl: ${textSizingValues.desktop.text3xl};
|
||||
--text-4xl: ${textSizingValues.desktop.text4xl};
|
||||
--text-5xl: ${textSizingValues.desktop.text5xl};
|
||||
--text-6xl: ${textSizingValues.desktop.text6xl};
|
||||
--text-7xl: ${textSizingValues.desktop.text7xl};
|
||||
--text-8xl: ${textSizingValues.desktop.text8xl};
|
||||
--text-9xl: ${textSizingValues.desktop.text9xl};
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
:root {
|
||||
--width-content-width: ${contentWidthValues.mobile};
|
||||
--width-content-width-expanded: ${expandedContentWidthValues.mobile};
|
||||
--vw: ${baseVwValues.mobile};
|
||||
--text-2xs: ${textSizingValues.mobile.text2xs};
|
||||
--text-xs: ${textSizingValues.mobile.textXs};
|
||||
--text-sm: ${textSizingValues.mobile.textSm};
|
||||
--text-base: ${textSizingValues.mobile.textBase};
|
||||
--text-lg: ${textSizingValues.mobile.textLg};
|
||||
--text-xl: ${textSizingValues.mobile.textXl};
|
||||
--text-2xl: ${textSizingValues.mobile.text2xl};
|
||||
--text-3xl: ${textSizingValues.mobile.text3xl};
|
||||
--text-4xl: ${textSizingValues.mobile.text4xl};
|
||||
--text-5xl: ${textSizingValues.mobile.text5xl};
|
||||
--text-6xl: ${textSizingValues.mobile.text6xl};
|
||||
--text-7xl: ${textSizingValues.mobile.text7xl};
|
||||
--text-8xl: ${textSizingValues.mobile.text8xl};
|
||||
--text-9xl: ${textSizingValues.mobile.text9xl};
|
||||
}
|
||||
}
|
||||
.card {
|
||||
${cardStyles}
|
||||
}
|
||||
${gradientBorderedPseudo}
|
||||
.primary-button {
|
||||
${primaryButtonStyles}
|
||||
}
|
||||
.secondary-button {
|
||||
${secondaryButtonStyles}
|
||||
}
|
||||
`;
|
||||
const bgClass = backgroundClasses[background as keyof typeof backgroundClasses] || backgroundClasses.aurora;
|
||||
const radiusClass = borderRadiusClasses[borderRadius as keyof typeof borderRadiusClasses] || borderRadiusClasses.soft;
|
||||
const widthClass = contentWidthClasses[contentWidth as keyof typeof contentWidthClasses] || contentWidthClasses.medium;
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={themeConfig}>
|
||||
<style>{styleString}</style>
|
||||
{BackgroundComponent && <BackgroundComponent />}
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
<div
|
||||
className={`${bgClass} min-h-screen transition-colors duration-300`}
|
||||
style={{
|
||||
'--default-button-variant': defaultButtonVariant,
|
||||
'--default-text-animation': defaultTextAnimation,
|
||||
'--card-style': cardStyle,
|
||||
'--primary-button-style': primaryButtonStyle,
|
||||
'--secondary-button-style': secondaryButtonStyle,
|
||||
'--heading-font-weight': headingFontWeight,
|
||||
} as React.CSSProperties}
|
||||
>
|
||||
<div className={`${widthClass} mx-auto px-4 sm:px-6 lg:px-8`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function TeamCardGrid({ members }: { members: TeamMember[] }) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 py-12">
|
||||
{members.map((member) => (
|
||||
<TeamCard key={member.id} member={member} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user