1

I'm rendering data cards for Pokemon. Each pokemon type has an associated color. Fire is red, water is blue, grass is green. Some pokemon have one type, some pokemon have 2 types.

I want the background color to be either solid if the pokemon has one type, but the tricky part is I want the background to be a gradient if the pokemon has two types. For example, a Fire pokemon would have a solid red background, whereas a water/grass pokemon would be a blue/green gradient.

There are 18 pokemon types. For a total of 324 combinations. I know I could hardcode classes for each combination .fire-ice{colors} but there has to be a better solution.

How can achieve this programatically? I'm using sass and react

Astrydax
  • 463
  • 3
  • 15
  • always consider 2 colors and in case of one type then both color are the same so you will always end with a gradient of two color that you can easily set inline or using CSS variables – Temani Afif Feb 15 '20 at 00:31

2 Answers2

0

1 - Setup an object to map power:color.

2 - Turn the pokemon powers array into colors array and join it to a string

3 - put the colors string inside background:linear-gradient(...) inline style

Take a look at the below code:

 const colors = {
  grass: 'green',
  fire: 'red',
  water: 'blue'
 }
 function getColor(powers){
  if(powers.length === 1) return colors[powers[0]];
  return 'linear-gradient('+powers.map(p=> colors[p]).join()+')';
 }

 // testing..
 const powers = [
  ['grass'],
  ['fire','water'],
  ['fire'],
  ['fire','water','grass']
 ];
 powers.forEach(p => console.log(getColor(p)));

for react, use <div style={{background: getColor(this.props.powers)}}/>

Yosef Tukachinsky
  • 5,570
  • 1
  • 13
  • 29
0

You can do this by setting the style (CSS) on your element dynamically based on the props passed. You just need a mapping from the Pokemon type to a color, and then just check if there is only one type or two, and use that to either set a background-color or background-image (using linear gradient).

For example:

const POKEMON_TYPES = {
    FIRE: "Fire",
    WATER: "Water",
    GRASS: "Grass",
}


const POKEMON_TYPE_COLORS = {
    [POKEMON_TYPES.FIRE]: "#ff0000",
    [POKEMON_TYPES.WATER]: "#0000ff",
    [POKEMON_TYPES.GRASS]: "#00ff00",
}


const App = () => {
    return (
        <div>
            <PokemonCard name="Fire Only" types={ [POKEMON_TYPES.FIRE] }/>
            <PokemonCard name="Fire And Water" types={ [POKEMON_TYPES.FIRE, POKEMON_TYPES.WATER] }/>
            <PokemonCard name="Water And Grass" types={ [POKEMON_TYPES.WATER, POKEMON_TYPES.GRASS] }/>
        </div>
    )
}


const PokemonCard = props => {
    const { name, types } = props;

    let style;
    if (types.length === 2) {
        const typeColor1 = POKEMON_TYPE_COLORS[types[0]];
        const typeColor2 = POKEMON_TYPE_COLORS[types[1]];
        style = {"backgroundImage": `linear-gradient(45deg, ${typeColor1}, ${typeColor2})`};
    } else {
        const typeColor = POKEMON_TYPE_COLORS[types[0]];
        style = {"backgroundColor": typeColor};
    }

    return (
        <div className="pokemon-card" style={ style }>
            { name }
        </div>
    )
}


ReactDOM.render(<App/>, document.querySelector("#root"));
.pokemon-card {
    color: #fff;
    width: 10rem;
    height: 5rem;
    padding: .75rem 1rem;
    margin-bottom: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="root"/>

You may want to add handling to sort the types first so that each combination is always displayed the same (no flips). Also you might consider using type and types as separate props (not sure how you have that set up currently), but it should be clear how to make that change.

You may also want to set the text color differently depending on the background color, this post may be helpful for you: https://stackoverflow.com/a/3943023/8068625.

Henry Woody
  • 14,024
  • 7
  • 39
  • 56