Skip to content

Commit

Permalink
Add theme context for images
Browse files Browse the repository at this point in the history
  • Loading branch information
Tymmmy committed Sep 21, 2024
1 parent 38aaf4b commit cef3c27
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
increaseQuantity,
removeFromCart
} from '@/lib/stores/cart-store.ts'
import { useThemeContext } from '@/lib/theme'
import { formatPrice } from '@/lib/utils.ts'
import { createContext, ReactNode, useContext } from 'react'
import { Link } from 'react-router-dom'
Expand All @@ -22,12 +23,13 @@ export const CartItemContext = createContext<CartItemContextValue>(
)

export const CartItem = ({ item }: CartItemProps) => {
const { theme } = useThemeContext()
return (
<CartItemContext.Provider value={{ item: item }}>
<li key={item.id} className="flex py-6 first-of-type:pt-0">
<div className="flex-shrink-0 rounded-md border border-green dark:border-pink-neon bg-green-light dark:bg-purple-dark">
<img
src={`${IMAGES_URL}${item.image}`}
src={`${IMAGES_URL}${theme === 'light' ? item.image : item.imageDark}`}
alt={item.name}
className="h-24 w-24 object-scale-down object-center"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IMAGES_URL } from '@/lib/constants.ts'
import { CartItem } from '@/lib/stores/cart-store.ts'
import { useThemeContext } from '@/lib/theme'
import { formatPrice } from '@/lib/utils.ts'

export interface Summary {
Expand All @@ -12,6 +13,7 @@ interface OrderSummaryProps {
}

export const OrderSummary = ({ summary }: OrderSummaryProps) => {
const { theme } = useThemeContext()
return (
<section className="row-start-1 rounded-md border border-green dark:border-pink-neon px-4 py-4 sm:px-6 lg:row-start-auto lg:border-0 lg:px-0 lg:pb-16">
<div className="mx-auto max-w-lg lg:max-w-none">
Expand All @@ -20,7 +22,7 @@ export const OrderSummary = ({ summary }: OrderSummaryProps) => {
{summary.items.map((item) => (
<li key={item.id} className="flex items-start space-x-4 py-6">
<img
src={`${IMAGES_URL}${item.image}`}
src={`${IMAGES_URL}${theme === 'light' ? item.image : item.imageDark}`}
alt={item.name}
className="h-20 w-20 flex-none rounded-md border border-green dark:border-pink-neon bg-green-light dark:bg-purple-dark object-scale-down object-center"
/>
Expand Down
11 changes: 7 additions & 4 deletions packages/boutique/frontend/src/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { QueryClientProvider } from '@tanstack/react-query'
import { queryClient } from './query-client.ts'
import { Toaster } from '@/components/ui/toaster.tsx'
import { cartRoutes } from './cart/routes.tsx'
import { ThemeProvider } from '@/components/theme-provider.tsx'
import { checkoutRoutes } from './checkout/routes.tsx'

const Index = () => {
Expand Down Expand Up @@ -49,9 +50,11 @@ const router = createBrowserRouter(routes)

export function App() {
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<Toaster />
</QueryClientProvider>
<ThemeProvider>
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<Toaster />
</QueryClientProvider>
</ThemeProvider>
)
}
4 changes: 3 additions & 1 deletion packages/boutique/frontend/src/app/products/$slug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createContext } from 'react'
import { Link } from 'react-router-dom'
import { ProductCTA } from './components/product-cta.tsx'
import { ProductShimmer } from './components/product-shimmer.tsx'
import { useThemeContext } from '@/lib/theme.ts'

interface ProductContextValue {
product: Product
Expand All @@ -18,6 +19,7 @@ export const ProductContext = createContext<ProductContextValue>(

export function Component() {
const { data, error } = useProductQuery()
const { theme } = useThemeContext()

if (error) {
return (
Expand All @@ -43,7 +45,7 @@ export function Component() {
<div className="lg:grid lg:grid-cols-3 lg:gap-x-12">
<div className="aspect-h-1 aspect-w-1 mx-auto h-80 w-80 overflow-hidden rounded-md bg-green-light dark:bg-purple-dark lg:w-full">
<img
src={`${IMAGES_URL}${data.result.image}`}
src={`${IMAGES_URL}${theme === 'light' ? data.result.image : data.result.image}`}
alt={data.result.name}
className="h-full w-full object-scale-down object-center"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import type { Product } from '@/hooks/use-products-query'
import { IMAGES_URL } from '@/lib/constants.ts'
import { fetcher } from '@/lib/fetcher.ts'
import { useThemeContext } from '@/lib/theme'
import { formatPrice } from '@/lib/utils.ts'
import { Link } from 'react-router-dom'

Expand All @@ -19,8 +20,9 @@ interface ProductCardProps {
}

export const ProductCard = ({ product }: ProductCardProps) => {
const { name, price, image, slug } = product
const imageUrl = `${IMAGES_URL}${image}`
const { name, price, image, imageDark, slug } = product
const { theme } = useThemeContext()
const imageUrl = `${IMAGES_URL}${theme === 'light' ? image : imageDark}`
return (
<Link
onMouseEnter={async () => {
Expand Down Expand Up @@ -60,7 +62,7 @@ export const ProductCard = ({ product }: ProductCardProps) => {
<CardContent className="p-0">
<img
className="absolute right-5 top-1/2 h-42 w-32 -translate-y-1/2 transition-[right]"
alt={image}
alt={theme === 'light' ? image : imageDark}
src={imageUrl}
/>
</CardContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { PopoverClose } from '@radix-ui/react-popover'
import { Link } from 'react-router-dom'
import { CartItem } from '@/lib/stores/cart-store.ts'
import { useState } from 'react'
import { useThemeContext } from '@/lib/theme.ts'

export const ShoppingCartPopover = () => {
const [open, setOpen] = useState(false)
Expand Down Expand Up @@ -70,10 +71,11 @@ interface ShoppingCartItemProps {
}

const ShoppingCartItem = ({ item }: ShoppingCartItemProps) => {
const { theme } = useThemeContext()
return (
<li className="flex items-center dark:text-white py-6 first-of-type:pt-0 focus:outline-none focus:ring-2 focus:ring-green dark:focus:ring-green-neon">
<img
src={`${IMAGES_URL}${item.image}`}
src={`${IMAGES_URL}${theme === 'light' ? item.image : item.imageDark}`}
alt={item.name}
className="h-12 w-12 flex-none rounded-md border border-green dark:border-pink-neon bg-green-light dark:bg-purple"
/>
Expand Down
21 changes: 21 additions & 0 deletions packages/boutique/frontend/src/components/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReactNode, useState } from 'react'
import { ThemeContext } from '../lib/theme'

type ThemeProviderProps = {
children: ReactNode
}

export const ThemeProvider = ({ children }: ThemeProviderProps) => {
const [theme, setTheme] = useState<'light' | 'dark'>('light')

return (
<ThemeContext.Provider
value={{
theme,
setTheme
}}
>
{children}
</ThemeContext.Provider>
)
}
7 changes: 4 additions & 3 deletions packages/boutique/frontend/src/components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { CSSProperties, useEffect, useState } from 'react'
import { useThemeContext } from '@/lib/theme'
import { CSSProperties, useEffect } from 'react'

export const ThemeToggle: React.FC = () => {
const [theme, setTheme] = useState<'light' | 'dark'>('light')
const { theme, setTheme } = useThemeContext()

const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'))
setTheme(theme === 'dark' ? 'light' : 'dark')
}

useEffect(() => {
Expand Down
20 changes: 20 additions & 0 deletions packages/boutique/frontend/src/lib/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createContext, useContext } from 'react'

type ThemeContextProps = {
theme: 'light' | 'dark'
setTheme: (theme: 'light' | 'dark') => void
}

export const ThemeContext = createContext<ThemeContextProps | null>(null)

export const useThemeContext = () => {
const themeContext = useContext(ThemeContext)

if (!themeContext) {
throw new Error(
'"useThemeContext" is used outside the ThemeContextProvider.'
)
}

return themeContext
}

0 comments on commit cef3c27

Please sign in to comment.