Skip to content

Commit

Permalink
feat: Add img component for light and dark src
Browse files Browse the repository at this point in the history
  • Loading branch information
calvin-codecov committed Jan 25, 2025
1 parent 02d5b6b commit 609cb2e
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 29 deletions.
10 changes: 4 additions & 6 deletions src/pages/CodecovAIPage/CodecovAICommands/CodecovAICommands.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import darkModeImage from 'assets/codecovAI/pr-review-example-dark-mode.png'
import lightModeImage from 'assets/codecovAI/pr-review-example-light-mode.png'
import { Theme, useThemeContext } from 'shared/ThemeContext'
import { Card } from 'ui/Card'
import { ExpandableSection } from 'ui/ExpandableSection'
import LightDarkImg from 'ui/LightDarkImg'

const CodecovAICommands: React.FC = () => {
const { theme } = useThemeContext()
const prReviewExampleSource =
theme === Theme.DARK ? darkModeImage : lightModeImage
return (
<div>
<Card>
Expand All @@ -34,10 +31,11 @@ const CodecovAICommands: React.FC = () => {
</p>
</ExpandableSection.Trigger>
<ExpandableSection.Content className="m-0 p-0">
<img
<LightDarkImg
className="size-full object-cover"
src={lightModeImage}
darkSrc={darkModeImage}
alt="codecov pr review example"
src={prReviewExampleSource}
/>
</ExpandableSection.Content>
</ExpandableSection>
Expand Down
19 changes: 12 additions & 7 deletions src/pages/RepoPage/CoverageOnboarding/GitHubActions/TokenStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import { useRepo } from 'services/repo'
import { useUploadTokenRequired } from 'services/uploadTokenRequired'
import { useIsCurrentUserAnAdmin } from 'services/user'
import { Provider } from 'shared/api/helpers'
import { Theme, useThemeContext } from 'shared/ThemeContext'
import A from 'ui/A'
import Button from 'ui/Button'
import { Card } from 'ui/Card'
import { CodeSnippet } from 'ui/CodeSnippet'
import { ExpandableSection } from 'ui/ExpandableSection'
import LightDarkImg from 'ui/LightDarkImg'
import { RadioTileGroup } from 'ui/RadioTileGroup'

export const TOKEN_OPTIONS = {
Expand Down Expand Up @@ -53,11 +53,6 @@ function GitHubOrgSecretExample({
uploadToken,
owner,
}: SecretGHExampleProps) {
const { theme } = useThemeContext()
const isDarkMode = theme === Theme.DARK
const orgSecretImg = isDarkMode ? orgSecretDark : orgSecretLight
const repoSecretImg = isDarkMode ? repoSecretDark : repoSecretLight

return (
<>
<p>
Expand Down Expand Up @@ -94,14 +89,24 @@ function GitHubOrgSecretExample({
</p>
</ExpandableSection.Trigger>
<ExpandableSection.Content>
<img
{/* <img
className="size-full object-cover"
alt={
isUsingGlobalToken
? 'org settings secret example'
: 'repo settings secret example'
}
src={isUsingGlobalToken ? orgSecretImg : repoSecretImg}
/> */}
<LightDarkImg
alt={
isUsingGlobalToken
? 'org settings secret example'
: 'repo settings secret example'
}
className="size-full object-cover"
src={isUsingGlobalToken ? orgSecretLight : repoSecretLight}
darkSrc={isUsingGlobalToken ? orgSecretDark : repoSecretDark}
/>
</ExpandableSection.Content>
</ExpandableSection>
Expand Down
12 changes: 4 additions & 8 deletions src/pages/RepoPage/FailedTestsTab/CodecovCLI/CodecovCLI.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import testsPRComment from 'assets/svg/onboardingTests/testsPRComment.svg'
import testsPRCommentDark from 'assets/svg/onboardingTests/testsPRCommentDark.svg'
import testsRunning from 'assets/svg/onboardingTests/testsRunning.svg'
import { Theme, useThemeContext } from 'shared/ThemeContext'
import A from 'ui/A'
import { Card } from 'ui/Card'
import { CodeSnippet } from 'ui/CodeSnippet'
import { ExpandableSection } from 'ui/ExpandableSection/ExpandableSection'
import LightDarkImg from 'ui/LightDarkImg'

import { FrameworkTabsCard } from '../FrameworkTabsCard'

Expand Down Expand Up @@ -110,11 +110,6 @@ function Step4() {
}

function Step5() {
const { theme } = useThemeContext()

const testPRsImageSource =
theme === Theme.LIGHT ? testsPRComment : testsPRCommentDark

return (
<div>
<Card>
Expand All @@ -141,10 +136,11 @@ function Step5() {
</p>
</ExpandableSection.Trigger>
<ExpandableSection.Content>
<img
src={testPRsImageSource.toString()}
<LightDarkImg
src={testsPRComment.toString()}
alt="Tests in PR comment"
className="w-full"
darkSrc={testsPRCommentDark.toString()}
/>
</ExpandableSection.Content>
</ExpandableSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import testsPRComment from 'assets/svg/onboardingTests/testsPRComment.svg'
import testsPRCommentDark from 'assets/svg/onboardingTests/testsPRCommentDark.svg'
import testsRunning from 'assets/svg/onboardingTests/testsRunning.svg'
import { Theme, useThemeContext } from 'shared/ThemeContext'
import A from 'ui/A'
import { Card } from 'ui/Card'
import { CodeSnippet } from 'ui/CodeSnippet'
import { ExpandableSection } from 'ui/ExpandableSection/ExpandableSection'
import LightDarkImg from 'ui/LightDarkImg'

import { FrameworkTabsCard } from '../FrameworkTabsCard'

Expand Down Expand Up @@ -103,11 +103,6 @@ function Step2() {
}

function Step3() {
const { theme } = useThemeContext()

const testPRsImageSource =
theme === Theme.LIGHT ? testsPRComment : testsPRCommentDark

return (
<div>
<Card>
Expand All @@ -134,10 +129,11 @@ function Step3() {
</p>
</ExpandableSection.Trigger>
<ExpandableSection.Content>
<img
src={testPRsImageSource.toString()}
<LightDarkImg
src={testsPRComment.toString()}
alt="Tests in PR comment"
className="w-full"
darkSrc={testsPRCommentDark.toString()}
/>
</ExpandableSection.Content>
</ExpandableSection>
Expand Down
58 changes: 58 additions & 0 deletions src/ui/LightDarkImg/LightDarkImg.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { type Meta, type StoryObj } from '@storybook/react'

import orgSecretDark from 'assets/onboarding/org_secret_dark.png'
import orgSecretLight from 'assets/onboarding/org_secret_light.png'
import {
Theme,
ThemeContextProvider,
useThemeContext,
} from 'shared/ThemeContext'

import LightDarkImg, { type LightDarkImgSrcProps } from './LightDarkImg'

const meta: Meta<typeof LightDarkImg> = {
title: 'Components/LightDarkImg',
component: LightDarkImg,
}

export default meta

type Story = StoryObj<typeof LightDarkImg>

const LightDarkImgElements = (args: LightDarkImgSrcProps) => {
const { theme, setTheme } = useThemeContext()
return (
<div>
<button
onClick={() =>
setTheme(theme === Theme.LIGHT ? Theme.DARK : Theme.LIGHT)
}
style={{
marginTop: '20px',
padding: '10px 20px',
backgroundColor: theme === 'light' ? '#000' : '#fff',
color: theme === 'light' ? '#fff' : '#000',
border: 'none',
borderRadius: '4px',
}}
>
Toggle Theme
</button>
<div>Current Theme: {theme}</div>
<LightDarkImg {...args} />
</div>
)
}

export const SimpleLightDarkImg: Story = {
args: {
alt: 'test text',
src: orgSecretLight,
darkSrc: orgSecretDark,
},
render: (args) => (
<ThemeContextProvider>
<LightDarkImgElements {...args} />
</ThemeContextProvider>
),
}
67 changes: 67 additions & 0 deletions src/ui/LightDarkImg/LightDarkImg.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { describe, expect, it, vi } from 'vitest'

import { Theme, ThemeContext } from 'shared/ThemeContext/ThemeContext'

import LightDarkImg from './LightDarkImg'

const wrapper = (theme: Theme) => {
return ({ children }: { children: React.ReactNode }) => {
return (
<ThemeContext.Provider value={{ theme, setTheme: vi.fn() }}>
{children}
</ThemeContext.Provider>
)
}
}

describe('LightDarkImg', () => {
const mockProps = {
src: '/light-image.png',
darkSrc: '/dark-image.png',
alt: 'Test image',
}

it('renders with light source in light mode', () => {
render(<LightDarkImg {...mockProps} />, { wrapper: wrapper(Theme.LIGHT) })

const img = screen.getByAltText('Test image')
expect(img).toBeInTheDocument()
expect(img).toHaveAttribute('src', '/light-image.png')
})

it('renders with dark source in dark mode', () => {
render(<LightDarkImg {...mockProps} />, { wrapper: wrapper(Theme.DARK) })

const img = screen.getByAltText('Test image')
expect(img).toBeInTheDocument()
expect(img).toHaveAttribute('src', '/dark-image.png')
})

it('falls back to light source when dark source is not provided', () => {
const propsWithoutDark = {
src: '/light-image.png',
alt: 'Test image',
}

render(<LightDarkImg {...propsWithoutDark} />, {
wrapper: wrapper(Theme.DARK),
})

const img = screen.getByAltText('Test image')
expect(img).toBeInTheDocument()
expect(img).toHaveAttribute('src', '/light-image.png')
})

it('passes through additional props to img element', () => {
render(
<LightDarkImg {...mockProps} className="w-10" data-testid="test-img" />,
{ wrapper: wrapper(Theme.LIGHT) }
)

const img = screen.getByAltText('Test image')
expect(img).toHaveClass('w-10')
expect(img).toHaveAttribute('data-testid', 'test-img')
})
})
26 changes: 26 additions & 0 deletions src/ui/LightDarkImg/LightDarkImg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react'

import { Theme, useThemeContext } from 'shared/ThemeContext'

export interface LightDarkImgSrcProps {
alt: string
src: string
darkSrc?: string
}

type LightDarkImgProps = Omit<
React.ImgHTMLAttributes<HTMLImageElement>,
'alt' | 'src'
> &
LightDarkImgSrcProps

function LightDarkImg({ src, darkSrc, alt, ...props }: LightDarkImgProps) {
const { theme } = useThemeContext()
const isDarkMode = theme === Theme.DARK

return (
<img {...props} alt={alt} src={isDarkMode && darkSrc ? darkSrc : src} />
)
}

export default LightDarkImg
1 change: 1 addition & 0 deletions src/ui/LightDarkImg/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './LightDarkImg'

0 comments on commit 609cb2e

Please sign in to comment.