Skip to content

Commit 3991676

Browse files
feat: implement slots rebranded
1 parent 8fe3bda commit 3991676

File tree

3 files changed

+306
-77
lines changed

3 files changed

+306
-77
lines changed
Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,166 @@
11
import classNames from 'classnames';
2-
import { HTMLAttributes } from 'react';
32

4-
// 👨🏻💻 1A - Add two new types of "iconLeft" & "iconRight"
5-
interface IButton extends HTMLAttributes<HTMLButtonElement> {
3+
// 👨🏻💻 1A - This component uses individual props for each map location. Can we refactor it to use slots instead?
4+
interface IPokemonMap {
65
className?: string;
7-
children: React.ReactNode | React.ReactNode[];
6+
7+
// North area props
8+
showNorthArea?: boolean;
9+
northAreaName?: string;
10+
northAreaIcon?: string;
11+
northAreaColor?: string;
12+
13+
// South area props
14+
showSouthArea?: boolean;
15+
southAreaName?: string;
16+
southAreaIcon?: string;
17+
southAreaColor?: string;
18+
19+
// East area props
20+
showEastArea?: boolean;
21+
eastAreaName?: string;
22+
eastAreaIcon?: string;
23+
eastAreaColor?: string;
24+
25+
// West area props
26+
showWestArea?: boolean;
27+
westAreaName?: string;
28+
westAreaIcon?: string;
29+
westAreaColor?: string;
30+
31+
// Center area props
32+
showCenterArea?: boolean;
33+
centerAreaName?: string;
34+
centerAreaIcon?: string;
35+
centerAreaColor?: string;
836
}
937

10-
const buttonClasses =
11-
'middle none center rounded-lg bg-blue-500 py-3 px-6 font-sans text-xs font-bold uppercase text-white shadow-md shadow-blue-500/20 transition-all hover:shadow-lg hover:shadow-blue-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none inline-flex items-center justify-center';
38+
const mapContainerClasses = 'grid grid-cols-3 grid-rows-3 gap-2 w-80 h-80 p-4 bg-green-100 rounded-lg border-2 border-green-300';
39+
const areaClasses = 'flex flex-col items-center justify-center p-3 rounded-lg border-2 text-sm font-bold text-white shadow-md';
1240

13-
// 👨🏻‍💻 1B - Extract those types out from the props and then add iconLeft above children and iconRight below
14-
// 💄 1C - styling - icon && <span className="mr-2 w-[1.5em] h-[1.5em]">{icon}</span>
15-
export const Button = ({ className, children, ...rest }: IButton) => {
41+
// 👨🏻💻 1B - Look at all these props and conditional logic! This is hard to maintain.
42+
// 👨🏻💻 1C - Refactor this to use northSlot, southSlot, eastSlot, westSlot, centerSlot instead
43+
export const PokemonMap = ({
44+
className,
45+
showNorthArea,
46+
northAreaName,
47+
northAreaIcon,
48+
northAreaColor,
49+
showSouthArea,
50+
southAreaName,
51+
southAreaIcon,
52+
southAreaColor,
53+
showEastArea,
54+
eastAreaName,
55+
eastAreaIcon,
56+
eastAreaColor,
57+
showWestArea,
58+
westAreaName,
59+
westAreaIcon,
60+
westAreaColor,
61+
showCenterArea,
62+
centerAreaName,
63+
centerAreaIcon,
64+
centerAreaColor
65+
}: IPokemonMap) => {
1666
return (
17-
<button
18-
{...rest}
19-
type="button"
20-
className={classNames(buttonClasses, className)}
21-
>
22-
{children}
23-
</button>
67+
<div className={classNames(mapContainerClasses, className)}>
68+
{/* Empty top-left */}
69+
<div></div>
70+
71+
{/* North area */}
72+
<div className={classNames(areaClasses, northAreaColor || 'bg-gray-400')}>
73+
{showNorthArea && (
74+
<>
75+
<span className="text-2xl mb-1">{northAreaIcon}</span>
76+
<span className="text-xs text-center">{northAreaName}</span>
77+
</>
78+
)}
79+
</div>
80+
81+
{/* Empty top-right */}
82+
<div></div>
83+
84+
{/* West area */}
85+
<div className={classNames(areaClasses, westAreaColor || 'bg-gray-400')}>
86+
{showWestArea && (
87+
<>
88+
<span className="text-2xl mb-1">{westAreaIcon}</span>
89+
<span className="text-xs text-center">{westAreaName}</span>
90+
</>
91+
)}
92+
</div>
93+
94+
{/* Center area */}
95+
<div className={classNames(areaClasses, centerAreaColor || 'bg-gray-400')}>
96+
{showCenterArea && (
97+
<>
98+
<span className="text-2xl mb-1">{centerAreaIcon}</span>
99+
<span className="text-xs text-center">{centerAreaName}</span>
100+
</>
101+
)}
102+
</div>
103+
104+
{/* East area */}
105+
<div className={classNames(areaClasses, eastAreaColor || 'bg-gray-400')}>
106+
{showEastArea && (
107+
<>
108+
<span className="text-2xl mb-1">{eastAreaIcon}</span>
109+
<span className="text-xs text-center">{eastAreaName}</span>
110+
</>
111+
)}
112+
</div>
113+
114+
{/* Empty bottom-left */}
115+
<div></div>
116+
117+
{/* South area */}
118+
<div className={classNames(areaClasses, southAreaColor || 'bg-gray-400')}>
119+
{showSouthArea && (
120+
<>
121+
<span className="text-2xl mb-1">{southAreaIcon}</span>
122+
<span className="text-xs text-center">{southAreaName}</span>
123+
</>
124+
)}
125+
</div>
126+
127+
{/* Empty bottom-right */}
128+
<div></div>
129+
</div>
24130
);
25131
};
26132

27-
// 👨🏻‍💻 1D - Add iconLeft={IconOne} from the icons folder to the first button
28-
// 👨🏻‍💻 1E - Add iconRight={IconTwo} from the icons folder to the second button
29-
// 👨🏻‍💻 1F - Add iconRight and iconLeft to the third button.
30-
// Check storybook, you should see some black icons.... Why?
31-
// 💅 2A - head over to ./icons/index.tsx
133+
// 👨🏻💻 1D - Look at how verbose these prop combinations are!
134+
// 👨🏻💻 1E - Refactor these to use slots: northSlot={<LocationCard />}, centerSlot={<TownCard />}, etc.
32135
export const Exercise = () => (
33-
<div className="grid grid-cols-1 gap-4 w-[300px]">
34-
<Button>Button one</Button>
35-
<Button>Button two</Button>
36-
<Button>Button three</Button>
136+
<div className="p-6 bg-blue-50 rounded-lg border-2 border-blue-200">
137+
<h2 className="text-2xl font-bold mb-4 text-blue-800">🗺️ Pokemon World Map</h2>
138+
139+
<PokemonMap
140+
showNorthArea={true}
141+
northAreaName="Viridian Forest"
142+
northAreaIcon="🌲"
143+
northAreaColor="bg-green-600"
144+
145+
showSouthArea={true}
146+
southAreaName="Route 1"
147+
southAreaIcon="🛤️"
148+
southAreaColor="bg-yellow-600"
149+
150+
showEastArea={true}
151+
eastAreaName="Power Plant"
152+
eastAreaIcon="⚡"
153+
eastAreaColor="bg-yellow-500"
154+
155+
showWestArea={true}
156+
westAreaName="Mt. Silver"
157+
westAreaIcon="🏔️"
158+
westAreaColor="bg-gray-600"
159+
160+
showCenterArea={true}
161+
centerAreaName="Pallet Town"
162+
centerAreaIcon="🏠"
163+
centerAreaColor="bg-blue-600"
164+
/>
37165
</div>
38-
);
166+
);
Lines changed: 127 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,140 @@
11
import classNames from 'classnames';
2-
import { HTMLAttributes } from 'react';
3-
import { IconOne, IconTwo } from '../icons';
42

5-
interface ButtonProps extends HTMLAttributes<HTMLButtonElement> {
3+
interface PokemonMapProps {
64
className?: string;
7-
iconLeft?: React.ReactNode;
8-
iconRight?: React.ReactNode;
9-
children: React.ReactNode | React.ReactNode[];
5+
northSlot?: React.ReactNode;
6+
southSlot?: React.ReactNode;
7+
eastSlot?: React.ReactNode;
8+
westSlot?: React.ReactNode;
9+
centerSlot?: React.ReactNode;
1010
}
1111

12-
const buttonClasses = [
13-
'middle none center rounded-lg bg-blue-500 py-3 px-6',
14-
'font-sans text-xs font-bold uppercase text-white',
15-
'shadow-md shadow-blue-500/20 transition-all',
16-
'hover:shadow-lg hover:shadow-blue-500/40',
17-
'focus:opacity-[0.85] focus:shadow-none',
18-
'active:opacity-[0.85] active:shadow-none',
19-
'disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none',
20-
'inline-flex items-center justify-center'
21-
].join(' ');
12+
const mapContainerClasses = 'grid grid-cols-3 grid-rows-3 gap-2 w-80 h-80 p-4 bg-green-100 rounded-lg border-2 border-green-300';
2213

23-
export const Button = ({
14+
export const PokemonMap = ({
2415
className,
25-
children,
26-
iconLeft,
27-
iconRight,
28-
...rest
29-
}: ButtonProps) => {
16+
northSlot,
17+
southSlot,
18+
eastSlot,
19+
westSlot,
20+
centerSlot
21+
}: PokemonMapProps) => {
3022
return (
31-
<button
32-
{...rest}
33-
type="button"
34-
className={classNames(buttonClasses, className)}
35-
>
36-
{iconLeft && (
37-
<span className="mr-2 w-[1.5em] h-[1.5em]">{iconLeft}</span>
38-
)}
39-
{children}
40-
{iconRight && (
41-
<span className="ml-2 w-[1.5em] h-[1.5em]">{iconRight}</span>
42-
)}
43-
</button>
23+
<div className={classNames(mapContainerClasses, className)}>
24+
{/* Empty top-left */}
25+
<div></div>
26+
27+
{/* North slot */}
28+
<div className="flex items-center justify-center">
29+
{northSlot}
30+
</div>
31+
32+
{/* Empty top-right */}
33+
<div></div>
34+
35+
{/* West slot */}
36+
<div className="flex items-center justify-center">
37+
{westSlot}
38+
</div>
39+
40+
{/* Center slot */}
41+
<div className="flex items-center justify-center">
42+
{centerSlot}
43+
</div>
44+
45+
{/* East slot */}
46+
<div className="flex items-center justify-center">
47+
{eastSlot}
48+
</div>
49+
50+
{/* Empty bottom-left */}
51+
<div></div>
52+
53+
{/* South slot */}
54+
<div className="flex items-center justify-center">
55+
{southSlot}
56+
</div>
57+
58+
{/* Empty bottom-right */}
59+
<div></div>
60+
</div>
4461
);
4562
};
4663

47-
export const Final = () => (
48-
<div className="grid grid-cols-1 gap-4 w-[300px]">
49-
<Button iconLeft={IconOne}>Button one</Button>
50-
<Button iconRight={IconTwo}>Button two</Button>
51-
<Button iconLeft={IconOne} iconRight={IconTwo}>
52-
Button three
53-
</Button>
64+
const LocationCard = ({ name, icon, bgColor }: { name: string; icon: string; bgColor: string }) => (
65+
<div className={`flex flex-col items-center justify-center p-3 rounded-lg border-2 text-sm font-bold text-white shadow-md w-full h-full ${bgColor}`}>
66+
<span className="text-2xl mb-1">{icon}</span>
67+
<span className="text-xs text-center">{name}</span>
5468
</div>
5569
);
70+
71+
export const Final = () => (
72+
<div className="p-6 bg-blue-50 rounded-lg border-2 border-blue-200">
73+
<h2 className="text-2xl font-bold mb-4 text-blue-800">🗺️ Pokemon World Map</h2>
74+
75+
<PokemonMap
76+
northSlot={
77+
<LocationCard
78+
name="Viridian Forest"
79+
icon="🌲"
80+
bgColor="bg-green-600"
81+
/>
82+
}
83+
southSlot={
84+
<LocationCard
85+
name="Route 1"
86+
icon="🛤️"
87+
bgColor="bg-yellow-600"
88+
/>
89+
}
90+
eastSlot={
91+
<LocationCard
92+
name="Power Plant"
93+
icon="⚡"
94+
bgColor="bg-yellow-500"
95+
/>
96+
}
97+
westSlot={
98+
<LocationCard
99+
name="Mt. Silver"
100+
icon="🏔️"
101+
bgColor="bg-gray-600"
102+
/>
103+
}
104+
centerSlot={
105+
<LocationCard
106+
name="Pallet Town"
107+
icon="🏠"
108+
bgColor="bg-blue-600"
109+
/>
110+
}
111+
/>
112+
113+
<div className="mt-6">
114+
<h3 className="text-lg font-bold mb-2 text-blue-800">Alternative Layout</h3>
115+
<PokemonMap
116+
centerSlot={
117+
<LocationCard
118+
name="Cerulean City"
119+
icon="💧"
120+
bgColor="bg-cyan-600"
121+
/>
122+
}
123+
northSlot={
124+
<LocationCard
125+
name="Cerulean Cave"
126+
icon="🕳️"
127+
bgColor="bg-purple-600"
128+
/>
129+
}
130+
eastSlot={
131+
<LocationCard
132+
name="Route 25"
133+
icon="🌊"
134+
bgColor="bg-blue-500"
135+
/>
136+
}
137+
/>
138+
</div>
139+
</div>
140+
);

0 commit comments

Comments
 (0)