diff --git a/app/components/ColorContextChangerContainer.tsx b/app/components/ColorContextChangerContainer.tsx
new file mode 100644
index 0000000..9d1b943
--- /dev/null
+++ b/app/components/ColorContextChangerContainer.tsx
@@ -0,0 +1,54 @@
+import { motion, useInView } from 'framer-motion';
+import { debounce } from 'lodash-es';
+import * as React from 'react';
+
+import { ColorContext } from '~/context/ColorContext';
+import type { ColorThemeContextEnum } from '~/context/types';
+
+export interface ColorChangeContainerProps {
+ children: React.ReactNode;
+ className?: string;
+ colorContext: ColorThemeContextEnum;
+ tag?: string;
+}
+
+export function ColorContextChangerContainer({
+ colorContext,
+ className,
+ tag,
+ children,
+}: ColorChangeContainerProps): React.ReactNode {
+ const ref = React.useRef(null);
+
+ const { setColorContext } = React.useContext(ColorContext);
+
+ const isInView = useInView(ref, { once: false, margin: '-500px' });
+
+ const debouncedColorContextHandler = debounce(
+ (debounceColorContext: ColorThemeContextEnum) => {
+ setColorContext(debounceColorContext);
+ },
+ 100,
+ );
+
+ React.useEffect(() => {
+ if (isInView) {
+ debouncedColorContextHandler(colorContext);
+ }
+ }, [isInView, colorContext, debouncedColorContextHandler]);
+
+ const CurrentTag = tag || 'div';
+ // @ts-expect-error Element mismatch between motion
+ const ColorContextChanger = motion[CurrentTag];
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/components/StaggerSplitText.tsx b/app/components/StaggerSplitText.tsx
new file mode 100644
index 0000000..98f692d
--- /dev/null
+++ b/app/components/StaggerSplitText.tsx
@@ -0,0 +1,39 @@
+import { motion } from 'framer-motion';
+import * as React from 'react';
+
+export function StaggerSplitText(props: { text: string }): React.ReactNode {
+ const { text } = props;
+
+ return (
+
+ {text.split('').map((individualLetter, individualLetterIndex) => (
+ ({
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.6,
+ delay: currentIndex * 0.04,
+ },
+ }),
+ }}
+ >
+ {individualLetter}
+
+ ))}
+
+ );
+}
diff --git a/app/context/ColorContext.tsx b/app/context/ColorContext.tsx
new file mode 100644
index 0000000..382d003
--- /dev/null
+++ b/app/context/ColorContext.tsx
@@ -0,0 +1,63 @@
+import { motion } from 'framer-motion';
+import { get } from 'lodash-es';
+import React, { createContext, useState } from 'react';
+
+import { ColorThemeContextEnum } from '~/context/types';
+import type { ColorContextState } from '~/context/types';
+import { useColorThemeResolver } from '~/hooks/useColorThemeResolver';
+
+export const ColorContext = createContext({
+ colorContext: ColorThemeContextEnum.DEFAULT,
+ setColorContext: (colorContext: ColorThemeContextEnum): void => {
+ /**
+ * as we need a default action to handle the param
+ */
+ // eslint-disable-next-line no-console
+ console.debug(colorContext);
+ },
+});
+
+export function BodyHTMLTagColorProvider({
+ children,
+}: {
+ children: React.ReactNode;
+}): React.ReactNode {
+ const { resolveColorTheme, colorThemeMap, colorTheme } =
+ useColorThemeResolver();
+
+ const [colors, setColors] = useState(
+ get(colorThemeMap, [ColorThemeContextEnum.DEFAULT]),
+ );
+
+ const setColorsHandler = (
+ selectedColorContext: ColorThemeContextEnum,
+ ): void => {
+ const { background, foreground } = resolveColorTheme(selectedColorContext);
+
+ setColors({ background, foreground });
+ };
+
+ const providerValue = React.useMemo(
+ () => ({
+ colorContext: colorTheme,
+ setColorContext: setColorsHandler,
+ }),
+ [colorTheme],
+ );
+
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/app/context/types.ts b/app/context/types.ts
new file mode 100644
index 0000000..d14dad7
--- /dev/null
+++ b/app/context/types.ts
@@ -0,0 +1,53 @@
+export type ColorContextState = {
+ background: string;
+ foreground: string;
+};
+
+export enum BaseColorsEnum {
+ WHITE = 'WHITE',
+ BLACK = 'BLACK',
+}
+
+export enum PrimaryColorsEnum {
+ RED = 'RED',
+ BLUE = 'BLUE',
+ YELLOW = 'YELLOW',
+}
+
+export enum SecondaryColorsEnum {
+ GREEN = 'GREEN',
+ ORANGE = 'ORANGE',
+ PURPLE = 'PURPLE',
+}
+
+type PrimaryColorsObject = {
+ [K in keyof typeof PrimaryColorsEnum]: string;
+};
+
+type SecondaryColorsObject = {
+ [K in keyof typeof SecondaryColorsEnum]: string;
+};
+
+type BaseColorsObject = {
+ [K in keyof typeof BaseColorsEnum]: string;
+};
+
+export type CombinedColorsObject = PrimaryColorsObject &
+ SecondaryColorsObject &
+ BaseColorsObject;
+
+export enum ColorThemeContextEnum {
+ BLUE = PrimaryColorsEnum.BLUE,
+ DEFAULT = BaseColorsEnum.BLACK,
+ WHITE = BaseColorsEnum.WHITE,
+ RED = PrimaryColorsEnum.RED,
+ YELLOW = PrimaryColorsEnum.YELLOW,
+
+ GREEN = SecondaryColorsEnum.GREEN,
+ ORANGE = SecondaryColorsEnum.ORANGE,
+ PURPLE = SecondaryColorsEnum.PURPLE,
+}
+
+export type ColorThemeContextMap = {
+ [K in ColorThemeContextEnum]: ColorContextState;
+};
diff --git a/app/hooks/useColorThemeResolver.ts b/app/hooks/useColorThemeResolver.ts
new file mode 100644
index 0000000..b3a2031
--- /dev/null
+++ b/app/hooks/useColorThemeResolver.ts
@@ -0,0 +1,91 @@
+import { get } from 'lodash-es';
+import { useState } from 'react';
+
+import {
+ BaseColorsEnum,
+ ColorThemeContextEnum,
+ PrimaryColorsEnum,
+ SecondaryColorsEnum,
+} from '~/context/types';
+import type {
+ ColorContextState,
+ ColorThemeContextMap,
+ CombinedColorsObject,
+} from '~/context/types';
+
+export type UseColorThemeResolver = () => {
+ colorTheme: ColorThemeContextEnum;
+ colorThemeMap: ColorThemeContextMap;
+ resolveColorTheme: (theme: ColorThemeContextEnum) => ColorContextState;
+};
+
+export const useColorThemeResolver: UseColorThemeResolver = () => {
+ const [colorTheme, setColorTheme] = useState(
+ ColorThemeContextEnum.DEFAULT,
+ );
+
+ const colors: {
+ [K in keyof CombinedColorsObject]: string;
+ } = {
+ [BaseColorsEnum.BLACK]: 'Black',
+ [BaseColorsEnum.WHITE]: 'GhostWhite',
+ [PrimaryColorsEnum.BLUE]: 'DarkBlue',
+ [PrimaryColorsEnum.RED]: 'Crimson',
+ [PrimaryColorsEnum.YELLOW]: 'Khaki',
+ [SecondaryColorsEnum.GREEN]: 'MediumSeaGreen',
+ [SecondaryColorsEnum.ORANGE]: 'DarkOrange',
+ [SecondaryColorsEnum.PURPLE]: 'Indigo',
+ };
+ const colorThemeMap: ColorThemeContextMap = {
+ [ColorThemeContextEnum.DEFAULT]: {
+ background: get(colors, [BaseColorsEnum.BLACK]),
+ foreground: get(colors, [PrimaryColorsEnum.RED]),
+ },
+ [ColorThemeContextEnum.WHITE]: {
+ background: get(colors, [BaseColorsEnum.WHITE]),
+ foreground: get(colors, [BaseColorsEnum.BLACK]),
+ },
+ [ColorThemeContextEnum.RED]: {
+ background: get(colors, [PrimaryColorsEnum.RED]),
+ foreground: get(colors, [SecondaryColorsEnum.GREEN]),
+ },
+ [ColorThemeContextEnum.GREEN]: {
+ background: get(colors, [SecondaryColorsEnum.GREEN]),
+ foreground: get(colors, [PrimaryColorsEnum.RED]),
+ },
+ [ColorThemeContextEnum.BLUE]: {
+ background: get(colors, [PrimaryColorsEnum.BLUE]),
+ foreground: get(colors, [SecondaryColorsEnum.ORANGE]),
+ },
+ [ColorThemeContextEnum.ORANGE]: {
+ background: get(colors, [SecondaryColorsEnum.ORANGE]),
+ foreground: get(colors, [PrimaryColorsEnum.BLUE]),
+ },
+ [ColorThemeContextEnum.PURPLE]: {
+ background: get(colors, [SecondaryColorsEnum.PURPLE]),
+ foreground: get(colors, [PrimaryColorsEnum.YELLOW]),
+ },
+ [ColorThemeContextEnum.YELLOW]: {
+ background: get(colors, [PrimaryColorsEnum.YELLOW]),
+ foreground: get(colors, [SecondaryColorsEnum.PURPLE]),
+ },
+ };
+
+ const resolveColorTheme = (
+ selectedColorContext: ColorThemeContextEnum,
+ ): ColorContextState => {
+ setColorTheme(selectedColorContext);
+
+ return get(
+ colorThemeMap,
+ [selectedColorContext],
+ get(colorThemeMap, [ColorThemeContextEnum.DEFAULT]),
+ );
+ };
+
+ return {
+ resolveColorTheme,
+ colorThemeMap,
+ colorTheme,
+ };
+};
diff --git a/app/lib/HorizontalScrollText.tsx b/app/lib/HorizontalScrollText.tsx
index 6ded13d..ee59e1b 100644
--- a/app/lib/HorizontalScrollText.tsx
+++ b/app/lib/HorizontalScrollText.tsx
@@ -80,7 +80,7 @@ export function HorizontalScrollText({
)}
style={{
lineHeight: '1.0',
- color: idx % 3 === 0 ? '#344054' : '#e0e6e6',
+ color: idx % 3 === 0 ? undefined : '#e0e6e6',
}}
>
{children}
diff --git a/app/root.tsx b/app/root.tsx
index 3f0dc0c..57eef1c 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -20,6 +20,7 @@ import {
} from '@remix-run/react';
import React from 'react';
+import { BodyHTMLTagColorProvider } from '~/context/ColorContext';
import '~/tailwind.css';
export const links: LinksFunction = () => [
@@ -49,14 +50,11 @@ export function Layout({
Kurocado Studio
-
+
{children}
-
+