Skip to content

Commit

Permalink
Refactore implementation of CardComponent background
Browse files Browse the repository at this point in the history
- remove _variables.scss

Co-authored-by: Felix Dimmel <12294922+GagaMen@users.noreply.github.com>
  • Loading branch information
TobiDimmel and GagaMen committed Nov 11, 2020
1 parent 8025058 commit fb12998
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 148 deletions.
18 changes: 1 addition & 17 deletions src/app/components/card/card.component.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,4 @@
<mat-card
[ngClass]="{
'type-action': card.types.includes(1),
'type-treasure': card.types.includes(27),
'type-victory': card.types.includes(28),
'type-reaction': card.types.includes(20),
'type-reserve': card.types.includes(21),
'type-duration': card.types.includes(8),
'type-night': card.types.includes(17),
'type-shelter': card.types.includes(23),
'type-ruins': card.types.includes(22),
'type-event': card.types.includes(9),
'type-landmark': card.types.includes(15),
'type-project': card.types.includes(19),
'type-way': card.types.includes(29)
}"
>
<mat-card [style.background]="color">
<mat-card-header>
<img
*ngIf="expansionIconUrl !== null"
Expand Down
118 changes: 1 addition & 117 deletions src/app/components/card/card.component.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@import '../../../scss/variables';

.expansion-icon {
border-radius: unset;
object-fit: contain;
Expand All @@ -10,6 +8,7 @@
font-weight: 700;
}

// TODO: fix use of 'type-...' classes after refactoring of background calculation
/* stylelint-disable-next-line selector-max-compound-selectors */
:host ::ng-deep .type-night:not(.type-duration) .mat-button-focus-overlay {
background: #fff;
Expand All @@ -34,118 +33,3 @@
.spacer {
flex-grow: 1;
}

.type-action {
background-color: $background-color-action;

&.type-duration {
background-color: $background-color-duration;
}

&.type-treasure {
background: linear-gradient($background-color-action 50%, $background-color-treasure 50%);
background-color: none;
}

&.type-victory {
background: linear-gradient($background-color-action 50%, $background-color-victory 50%);
background-color: none;
}

&.type-shelter {
background: linear-gradient($background-color-action 50%, $background-color-shelter 50%);
background-color: none;
}
}

.type-treasure {
background-color: $background-color-treasure;

&.type-reserve {
background: linear-gradient($background-color-treasure 50%, $background-color-reserve 50%);
background-color: none;
}

&.type-victory {
background: linear-gradient($background-color-treasure 50%, $background-color-victory 50%);
background-color: none;
}

&.type-reaction {
background: linear-gradient($background-color-treasure 50%, $background-color-reaction 50%);
background-color: none;
}
}

.type-victory {
background-color: $background-color-victory;

&.type-shelter {
background: linear-gradient($background-color-victory 50%, $background-color-shelter 50%);
background-color: none;
}

&.type-reaction {
background: linear-gradient($background-color-victory 50%, $background-color-reaction 50%);
background-color: none;
}
}

.type-reaction {
background-color: $background-color-reaction;

&.type-shelter {
background: linear-gradient($background-color-reaction 50%, $background-color-shelter 50%);
background-color: none;
}
}

.type-reserve {
background-color: $background-color-reserve;

&.type-victory {
background: linear-gradient($background-color-reserve 50%, $background-color-victory 50%);
background-color: none;
}
}

.type-duration {
background-color: $background-color-duration;

&.type-reaction {
background: linear-gradient($background-color-duration 50%, $background-color-reaction 50%);
background-color: none;
}
}

.type-night {
background-color: $background-color-night;

&.type-duration {
background-color: $background-color-duration;
}
}

.type-shelter {
background-color: $background-color-shelter;
}

.type-ruins {
background-color: $background-color-ruins;
}

.type-event {
background-color: $background-color-event;
}

.type-landmark {
background-color: $background-color-landmark;
}

.type-project {
background-color: $background-color-project;
}

.type-way {
background-color: $background-color-way;
}
130 changes: 130 additions & 0 deletions src/app/components/card/card.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
MatCardAvatar,
MatCardTitle,
MatCardSubtitle,
MatCard,
} from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { DataFixture } from 'src/testing/data-fixture';
Expand Down Expand Up @@ -83,6 +84,124 @@ describe('CardComponent', () => {
});
});

describe('color', () => {
const calculateColor = (topCardType: CardType, bottomCardType?: CardType) => {
const topColor = CardComponent.colorOfCardTypes.get(topCardType);
const bottomColor = bottomCardType
? CardComponent.colorOfCardTypes.get(bottomCardType)
: undefined;

if (topColor && bottomColor) {
return `linear-gradient(${topColor} 50%, ${bottomColor} 50%)`;
}
if (topColor) {
return topColor;
}

return '';
};
const cardTypeCompinations = [
{ types: [CardType.Action], expected: calculateColor(CardType.Action) },
{ types: [CardType.Duration], expected: calculateColor(CardType.Duration) },
{ types: [CardType.Event], expected: calculateColor(CardType.Event) },
{ types: [CardType.Landmark], expected: calculateColor(CardType.Landmark) },
{ types: [CardType.Night], expected: calculateColor(CardType.Night) },
{ types: [CardType.Project], expected: calculateColor(CardType.Project) },
{ types: [CardType.Reaction], expected: calculateColor(CardType.Reaction) },
{ types: [CardType.Reserve], expected: calculateColor(CardType.Reserve) },
{ types: [CardType.Ruins], expected: calculateColor(CardType.Ruins) },
{ types: [CardType.Shelter], expected: calculateColor(CardType.Shelter) },
{ types: [CardType.Treasure], expected: calculateColor(CardType.Treasure) },
{ types: [CardType.Victory], expected: calculateColor(CardType.Victory) },
{ types: [CardType.Way], expected: calculateColor(CardType.Way) },
{
types: [CardType.Action, CardType.Duration],
expected: calculateColor(CardType.Duration),
},
{
types: [CardType.Action, CardType.Night],
expected: calculateColor(CardType.Action),
},
{
types: [CardType.Action, CardType.Reaction],
expected: calculateColor(CardType.Reaction),
},
{
types: [CardType.Action, CardType.Ruins],
expected: calculateColor(CardType.Ruins),
},
{
types: [CardType.Action, CardType.Shelter],
expected: calculateColor(CardType.Action, CardType.Shelter),
},
{
types: [CardType.Action, CardType.Treasure],
expected: calculateColor(CardType.Action, CardType.Treasure),
},
{
types: [CardType.Action, CardType.Victory],
expected: calculateColor(CardType.Action, CardType.Victory),
},
{
types: [CardType.Duration, CardType.Reaction],
expected: calculateColor(CardType.Duration, CardType.Reaction),
},
{
types: [CardType.Night, CardType.Duration],
expected: calculateColor(CardType.Duration),
},
{
types: [CardType.Reaction, CardType.Shelter],
expected: calculateColor(CardType.Reaction, CardType.Shelter),
},
{
types: [CardType.Reserve, CardType.Victory],
expected: calculateColor(CardType.Reserve, CardType.Victory),
},
{
types: [CardType.Treasure, CardType.Reserve],
expected: calculateColor(CardType.Treasure, CardType.Reserve),
},
{
types: [CardType.Treasure, CardType.Victory],
expected: calculateColor(CardType.Treasure, CardType.Victory),
},
{
types: [CardType.Treasure, CardType.Reaction],
expected: calculateColor(CardType.Treasure, CardType.Reaction),
},
{
types: [CardType.Victory, CardType.Shelter],
expected: calculateColor(CardType.Victory, CardType.Shelter),
},
{
types: [CardType.Victory, CardType.Reaction],
expected: calculateColor(CardType.Victory, CardType.Reaction),
},
{
types: [CardType.Action, CardType.Duration, CardType.Reaction],
expected: calculateColor(CardType.Duration, CardType.Reaction),
},
{
types: [CardType.Action, CardType.Reserve, CardType.Victory],
expected: calculateColor(CardType.Reserve, CardType.Victory),
},
];

it('with card has given card types should return correct color', () => {
cardTypeCompinations.forEach(({ types, expected }) => {
component.card = dataFixture.createCard({ types: types });

const actual = component.color;

expect(actual).toBe(
expected,
`for types [${types.map((type) => CardType[type]).join(', ')}]`,
);
});
});
});

describe('template', () => {
let expansionIconUrlSpy: jasmine.Spy;

Expand All @@ -91,6 +210,17 @@ describe('CardComponent', () => {
expansionIconUrlSpy.and.returnValue(expansionIconUrl);
});

it('should bind "background" style of MatCard correctly', () => {
const color = '#999';
const expected = 'rgb(153, 153, 153)';
spyOnProperty(component, 'color').and.returnValue(color);
fixture.detectChanges();

const actual = fixture.debugElement.query(By.directive(MatCard)).styles.background;

expect(actual).toBe(expected);
});

it('with expansionIconUrl is null should not display MatCardAvatar', () => {
expansionIconUrlSpy.and.returnValue(null);
fixture.detectChanges();
Expand Down
76 changes: 76 additions & 0 deletions src/app/components/card/card.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ import { CardType } from 'src/app/models/card-type';
styleUrls: ['./card.component.scss'],
})
export class CardComponent {
static readonly colorOfCardTypes: Map<CardType, string> = new Map([
[CardType.Action, '#ede4c7'],
[CardType.Duration, '#f89a43'],
[CardType.Event, '#bbbeb7'],
[CardType.Landmark, '#59ac68'],
[CardType.Night, '#5d6a73'],
[CardType.Project, '#f5afad'],
[CardType.Reaction, '#aeb1d2'],
[CardType.Reserve, '#d5bd59'],
[CardType.Ruins, '#956415'],
[CardType.Shelter, '#e58265'],
[CardType.Treasure, '#fff095'],
[CardType.Victory, '#adcd2a'],
[CardType.Way, '#d3eef9'],
]);

@Input() card: Card = NullCard;
@Output() reshuffle: EventEmitter<undefined> = new EventEmitter<undefined>();

Expand All @@ -20,4 +36,64 @@ export class CardComponent {
get typesLabel(): string {
return this.card.types.map<string>((type: CardType) => CardType[type]).join(' - ');
}

get color(): string {
const orderedPrimaryCardTypes = [
CardType.Duration,
CardType.Treasure,
CardType.Reserve,
CardType.Victory,
CardType.Reaction,
CardType.Shelter,
CardType.Event,
CardType.Ruins,
CardType.Landmark,
CardType.Project,
CardType.Way,
];
const orderedSecondaryCardTypes = [CardType.Action, CardType.Night];

const primaryCardTypes = orderedPrimaryCardTypes.filter((cardType: CardType) =>
this.card.types.includes(cardType),
);
const secondaryCardTypes = orderedSecondaryCardTypes.filter((cardType: CardType) =>
this.card.types.includes(cardType),
);

// exception rules
if (
secondaryCardTypes[0] === CardType.Action &&
(primaryCardTypes[0] === CardType.Treasure ||
primaryCardTypes[0] === CardType.Victory ||
primaryCardTypes[0] === CardType.Shelter)
) {
return this.calculateColor(secondaryCardTypes[0], primaryCardTypes[0]);
}

// general rules
if (primaryCardTypes.length === 1) {
return this.calculateColor(primaryCardTypes[0]);
}
if (primaryCardTypes.length > 1) {
return this.calculateColor(primaryCardTypes[0], primaryCardTypes[1]);
}

return this.calculateColor(secondaryCardTypes[0]);
}

private calculateColor(topCardType: CardType, bottomCardType?: CardType): string {
const topColor = CardComponent.colorOfCardTypes.get(topCardType);
const bottomColor = bottomCardType
? CardComponent.colorOfCardTypes.get(bottomCardType)
: undefined;

if (topColor && bottomColor) {
return `linear-gradient(${topColor} 50%, ${bottomColor} 50%)`;
}
if (topColor) {
return topColor;
}

return '';
}
}

0 comments on commit fb12998

Please sign in to comment.