Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"eslint.format.enable": true,
"cSpell.words": []
"cSpell.words": [],
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}
Binary file added src/assets/poster.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 9 additions & 27 deletions src/components/Card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,31 @@ export const Card = ({ celebrity, level, visible }: CardProps) => {

const history = useHistory()

const levelMapping: Record<string, { size: number; s: number }> = {
0: { size: 20, s: 2 },
1: { size: 30, s: 3 },
2: { size: 40, s: 4 },
3: { size: 60, s: 6 },
4: { size: 80, s: 8 },
5: { size: 100, s: 10 },
6: { size: 120, s: 12 },
7: { size: 140, s: 14 },
8: { size: 180, s: 18 },
}
// getCssColorByCelebrity({ celebrity, border: true })

return (
<button
type="button"
className="shadow group overflow-hidden m-[1px] transition-all duration-200"
className={clsx("shadow-lg bg-white group overflow-hidden transition-all duration-200 mb-3 rounded-xl border-b-4 hover:-translate-y-2", getCssColorByCelebrity({ celebrity, border: true }))}
onClick={() => {
history.push(`/profile/${id}`)
}}
style={{
width: `${levelMapping[level].size}px`,
}}
>
<div className="relative">
<div
className={clsx(
'absolute inset-0 opacity-40 group-hover:hidden z-30 transition-all duration-500',
getCssColorByCelebrity({ celebrity, background: true }),
)}
/>

<img
src={imageUrl}
alt={name}
className="w-full grayscale group-hover:grayscale-0 transition-all duration-500"
className="w-full grayscale bg-gray-300 group-hover:grayscale-0 transition-all duration-500 rounded-t-lg"
/>
</div>
{visible && (
<div
className="p-[1px] text-center"
style={{ fontSize: `${levelMapping[level].s}px` }}
>
{name}
<div className='p-3'>
<div
className="p-[1px] font-semibold text-left"
>
{name}
</div>
</div>
)}
</button>
Expand Down
40 changes: 0 additions & 40 deletions src/components/Controls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,45 +49,5 @@ export const Controls = ({
)}
</button>
</div>
<div className="rounded-md w-10 h-20 flex flex-col overflow-hidden">
<button
className="flex-1 text-2xl bg-slate-800 hover:bg-slate-700 disabled:bg-slate-500 text-slate-100 disabled:text-slate-300 justify-center items-center flex"
type="button"
onClick={() => setLevel(level + 1)}
disabled={level === 8}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-6 h-6"
>
<path
fillRule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clipRule="evenodd"
/>
</svg>
</button>
<button
className="flex-1 text-2xl bg-slate-800 hover:bg-slate-700 disabled:bg-slate-500 text-slate-100 disabled:text-slate-300 justify-center items-center flex"
type="button"
onClick={() => setLevel(level - 1)}
disabled={level === 0}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-6 h-6"
>
<path
fillRule="evenodd"
d="M3.75 12a.75.75 0 01.75-.75h15a.75.75 0 010 1.5h-15a.75.75 0 01-.75-.75z"
clipRule="evenodd"
/>
</svg>
</button>
</div>
</div>
)
31 changes: 18 additions & 13 deletions src/components/Grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@ import React from 'react'

import { data } from '../../data/data'
import { Celebrity } from '../../types'
import { clsx, getCssColorByStatus } from '../../utils'
import { Card } from '../Card'
import { Controls } from '../Controls'
import { SearchInput } from '../SearchInput'

export const Grid = () => {
const [level, setLevel] = React.useState<number>(6)
const [visible, setVisible] = React.useState<boolean>(true)
const [query, setQuery] = React.useState('')
const [status, setStatus] = React.useState<Celebrity['status'] | null>(null)
export type GridProps = {
query: string
setQuery: (value: string) => void
visible: boolean
setVisible: (value: boolean) => void
level: number
setLevel: (value: number) => void
status: Celebrity['status'] | null
setStatus: (value: Celebrity['status'] | null) => void
}

export const Grid = ({ query, setQuery, visible, setVisible, level, setLevel, status, setStatus }: GridProps) => {
const { celebrities } = data

const renderBoxes = () =>
Expand All @@ -26,19 +34,16 @@ export const Grid = () => {
})

return (
<div className="flex flex-wrap justify-center content-start h-screen">
{renderBoxes()}
<div className="max-w-6xl mx-auto">
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-y-7 gap-x-5 px-10 lg:px-0">
{renderBoxes()}
</div>
<Controls
level={level}
setLevel={setLevel}
visible={visible}
setVisible={setVisible}
/>
<SearchInput
query={query}
setQuery={setQuery}
filter={{ status, setStatus }}
/>
</div>
)
}
}
32 changes: 32 additions & 0 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import { useHistory } from 'react-router-dom'
import { Celebrity } from '../../types'
import { clsx, getCssColorByCelebrity } from '../../utils'
import { SearchInput } from '../SearchInput'

export type HeaderProps = {
query: string
setQuery: (value: string) => void
status: Celebrity['status'] | null
setStatus: (value: Celebrity['status'] | null) => void
}

export const Header = ({ query, setQuery, status, setStatus }: HeaderProps) => {
const history = useHistory()

return (
<div className='relative bg-zinc-900 border-b shadow'>
<div className='mx-auto max-w-6xl h-16 flex items-center justify-between px-10 lg:px-0'>
<p className='text-base md:text-2xl text-white font-black'>Celebrity Wall</p>
<div>
<SearchInput
query={query}
setQuery={setQuery}
filter={{ status, setStatus }}
theme="dark"
/>
</div>
</div>
</div>
)
}
68 changes: 68 additions & 0 deletions src/components/Hero/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react'
import { useHistory } from 'react-router-dom'
import { clsx, getCssColorByStatus } from '../../utils'
import MahsaAminiHero from '../../assets/poster.png'
import { SearchInput } from '../SearchInput'
import { Celebrity } from '../../types'

export type HeroProps = {
query: string
setQuery: (value: string) => void
status: Celebrity['status'] | null
setStatus: (value: Celebrity['status'] | null) => void
}

export const Hero = ({ query, setQuery, status, setStatus }: HeroProps) => {
const history = useHistory()

return (
<div className="flex flex-col gap-2 items-center bg-gray-200 rounded-b-3xl mb-16 justify-center text-center">
<div className='max-w-6xl mx-auto'>
<div className='relative grid grid-cols-1 md:grid-cols-6 lg:grid-cols-5'>
<div className='col-span-4 lg:col-span-3 px-10 py-10 lg:px-0 lg:py-10 text-start z-10'>
<div className='space-y-10'>
<div>
<h1 className="text-6xl font-black">Celebrity Wall</h1>
<h2 className='text-3xl font-medium mb-3'>Rate the Celebrities</h2>
<p className="text-base w-3/4">
The goal of this project is to provide a big picture of celebrities
and their stance regarding what is happening in Iran.
</p>
</div>

<div className='space-y-3'>
<button
className={clsx('flex items-center gap-x-2 cursor-pointer', (status === 'GOOD' ? 'bg-emerald-500 text-white pr-3 rounded-full' : 'bg-transparent'))}
onClick={() => { if (status === 'GOOD') { setStatus(null) } else { setStatus('GOOD') } }}
type="button"
>
<span className={clsx('w-6 h-6 inline-block rounded-full', getCssColorByStatus({ status: 'GOOD', background: true }))} />
<span className='text-base'>Supported in cause</span>
</button>
<button
className={clsx('flex items-center gap-x-2 cursor-pointer', (status === 'UGLY' ? 'bg-gray-500 text-white pr-3 rounded-full' : 'bg-transparent'))}
onClick={() => { if (status === 'UGLY') { setStatus(null) } else { setStatus('UGLY') } }}
type="button"
>
<span className={clsx('w-6 h-6 inline-block rounded-full', getCssColorByStatus({ status: 'UGLY', background: true }))} />
<span className='text-base'>Didn&apos;t react to the cause</span>
</button>
<button
className={clsx('flex items-center gap-x-2 cursor-pointer', (status === 'BAD' ? 'bg-red-500 text-white pr-3 rounded-full' : 'bg-transparent'))}
onClick={() => { if (status === 'BAD') { setStatus(null) } else { setStatus('BAD') } }}
type="button"
>
<span className={clsx('w-6 h-6 inline-block rounded-full', getCssColorByStatus({ status: 'BAD', background: true }))} />
<span className='text-base'>Against the cause</span>
</button>
</div>
</div>
</div>
<div className='absolute bottom-0 w-full opacity-10 md:opacity-100 z-0 md:relative col-span-2 lg:col-span-2 flex justify-end content-end items-end align-bottom'>
<img src={MahsaAminiHero} alt='Mahsa Amini Poster' className='w-3/4 mx-auto' />
</div>
</div>
</div>
</div>
)
}
13 changes: 8 additions & 5 deletions src/components/SearchInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import React from 'react'
import { clsx } from '../../utils'
import { StatusFilterProps, StatusFilter } from './StatusFilter'

export type SearchInputProps = {
query: string
setQuery: (value: string) => void
filter: StatusFilterProps
filter: StatusFilterProps,
theme: string
}

export const SearchInput = ({
query,
setQuery,
filter: { status, setStatus },
theme = 'light',
}: SearchInputProps) => {
const onChange = (event: { target: { value: string } }) => {
setQuery(event?.target?.value)
}
return (
<div className="fixed z-50 left-4 bottom-4 flex flex-col gap-2">
<StatusFilter status={status} setStatus={setStatus} />
<div className="bg-slate-800 rounded-md p-2 text-slate-100 shadow">
<div className="flex flex-col gap-2">
{/* <StatusFilter status={status} setStatus={setStatus} /> */}
<div className={clsx("rounded-md p-2 w-full shadow flex", (theme === 'light' ? 'bg-white text-gray-700' : 'bg-zinc-800 text-zinc-300'))}>
<svg
className="float-left"
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -31,7 +34,7 @@ export const SearchInput = ({
</svg>
<input
type="text"
className="bg-transparent focus:outline-none ml-2"
className={clsx("bg-transparent focus:outline-none ml-2 w-full", (theme === 'light' ? 'text-black' : 'text-white'))}
placeholder="Search celebrity"
onChange={onChange}
value={query}
Expand Down
6 changes: 3 additions & 3 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
@tailwind components;
@tailwind utilities;

@import url('https://fonts.googleapis.com/css2?family=Lato:wght@100;300;400;700;900&display=swap');

body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family: 'Lato', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Expand Down
59 changes: 16 additions & 43 deletions src/pages/HomePage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,21 @@
import React from 'react'

import { Grid } from '../../components/Grid'
import { clsx, getCssColorByStatus } from '../../utils'
import { Header } from '../../components/Header'
import { Hero } from '../../components/Hero'
import { Celebrity } from '../../types'

export const HomePage = () => (
<div className="flex flex-col">
<div className="flex flex-col gap-2 items-center p-5 text-center">
<h1 className="text-4xl font-bold">Celebrity Wall</h1>
<div className="flex flex-col gap-1 items-center">
<p className="text-lg">
The goal of this project is to provide a big picture of celebrities
and their stance regarding what is happening in Iran.
</p>
<p className="text-lg">
<p
className={clsx(
'inline font-bold text-white px-1',
getCssColorByStatus({ status: 'GOOD', background: true }),
)}
>
Green celebrities
</p>{' '}
supported the cause,{' '}
<p
className={clsx(
'inline font-bold text-white px-1',
getCssColorByStatus({ status: 'UGLY', background: true }),
)}
>
gray celebrities
</p>{' '}
didn&apos;t react to the cause, and{' '}
<p
className={clsx(
'inline font-bold text-white px-1',
getCssColorByStatus({ status: 'BAD', background: true }),
)}
>
red celebrities
</p>{' '}
are against the cause!
</p>
</div>
export const HomePage = () => {
const [level, setLevel] = React.useState<number>(6)
const [visible, setVisible] = React.useState<boolean>(true)
const [query, setQuery] = React.useState('')
const [status, setStatus] = React.useState<Celebrity['status'] | null>(null)

return (
<div className="flex flex-col bg-gray-50">
<Header query={query} setQuery={setQuery} status={status} setStatus={setStatus} />
<Hero query={query} setQuery={setQuery} status={status} setStatus={setStatus} />
<Grid query={query} setQuery={setQuery} visible={visible} setVisible={setVisible} level={level} setLevel={setLevel} status={status} setStatus={setStatus} />
</div>
<Grid />
</div>
)
)
}
Loading