Skip to content

Commit

Permalink
Use F1 font for card headers (#116)
Browse files Browse the repository at this point in the history
* Use F1 font for card headers
* Added config option to use f1 font on headers

---------

Co-authored-by: Marco Kreeft <marco.kreeft@gmail.com>
  • Loading branch information
topscoder and marcokreeft87 authored Jan 29, 2023
1 parent 5a90348 commit 9865b4f
Show file tree
Hide file tree
Showing 20 changed files with 100 additions and 60 deletions.
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v18
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ or added by clicking the "Add to lovelace" button on the HACS dashboard after in
| image_clickable | boolean | `false` | Click on image leads to wikipedia, or not |
| show_carnumber | boolean | `false` | Show the number of the car |
| show_raceinfo | boolean | `false` | Show the info of the race in the countdown card |
| f1_font | boolean | `false` | Use the official F1 font for headers |
| location_clickable| boolean | `false` | Click on the location leads to wikipedia |
| previous_race | enum | | Hide/strikethrough or make the past races italic options are (hide, strikethrough or italic) |
| standings | object | | Configuration for the driver standings card |
Expand Down Expand Up @@ -172,6 +173,12 @@ card_type: countdown
```
![image](https://user-images.githubusercontent.com/10223677/213435405-fdb2ff7c-3364-43d5-80b0-0f253d9b60c8.png)
```
type: custom:formulaone-card
card_type: countdown
f1_font: true
```
## Translations
The following texts can be translated or altered.
Expand Down Expand Up @@ -238,5 +245,5 @@ translations:
- [ ] Qualifying result card (https://ergast.com/mrd/methods/qualifying/)
- [ ] Sprint result card (https://ergast.com/mrd/methods/sprint/)
- [ ] Live timing poc (https://livetiming.formula1.com/static/2022/2022-11-20_Abu_Dhabi_Grand_Prix/2022-11-20_Race/RaceControlMessages.json)
- [ ] Use F1 font
- [x] Use F1 font
- [ ] Editor
27 changes: 15 additions & 12 deletions formulaone-card.js

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions formulaone-card.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@
* Copyright 2021 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/

/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
Binary file modified formulaone-card.js.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ module.exports = {
testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
setupFiles: [ "<rootDir>/tests/config.ts" ],
collectCoverageFrom: ["**/src/**/*.{js,jsx,ts}", "!**/node_modules/**", "!**/vendor/**","!**/src/styles.ts"],
transformIgnorePatterns: ["node_modules\/(?!(lit|lit-element|lit-html|@lit)\/)"],
collectCoverageFrom: ["**/src/**/*.{js,jsx,ts}", "!**/node_modules/**", "!**/vendor/**","!**/src/styles.ts","!**/src/fonts.ts"],
transformIgnorePatterns: ["node_modules\/(?!(lit|lit-element|lit-html|@lit)\/)"]
};
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formulaone-card",
"version": "0.7.1",
"version": "0.8.0",
"description": "Frontend card for Home Assistant to display Formula One data",
"main": "index.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions src/cards/countdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ export default class Countdown extends BaseCard {
})} class="${(hasConfigAction ? 'clickable' : null)}">
<tr>
<td>
<h2><img height="25" src="${getCountryFlagByName(nextRace.Circuit.Location.country)}">&nbsp;&nbsp; ${nextRace.round} : ${nextRace.raceName}</h2>
<h2 class="${(this.config.f1_font ? 'formulaone-font' : '')}"><img height="25" src="${getCountryFlagByName(nextRace.Circuit.Location.country)}">&nbsp;&nbsp; ${nextRace.round} : ${nextRace.raceName}</h2>
</td>
</tr>
<tr>
<td class="text-center">
<h1>${asyncReplace(timer)}</h1>
<h1 class="${(this.config.f1_font ? 'formulaone-font' : '')}">${asyncReplace(timer)}</h1>
</td>
</tr>
</table>
Expand Down
9 changes: 9 additions & 0 deletions src/fonts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const loadCustomFonts = () => {

if(window && document.fonts) {
// Load the F1 font using the CSS Font Loading API
const font = new FontFace("F1Bold", "url(https://www.formula1.com/etc/designs/fom-website/fonts/F1Bold/Formula1-Bold.woff)");
document.fonts.add(font);
font.load();
}
}
28 changes: 15 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HomeAssistant } from 'custom-card-helpers';
import { FormulaOneCardConfig, FormulaOneCardType } from './types/formulaone-card-types';
import { CSSResult, html, HTMLTemplateResult, LitElement, PropertyValues } from 'lit';
import { checkConfig, hasConfigOrCardValuesChanged } from './utils';
import { loadCustomFonts } from './fonts';
import { styles } from './styles';
import ConstructorStandings from './cards/constructor-standings';
import DriverStandings from './cards/driver-standings';
Expand Down Expand Up @@ -42,13 +43,13 @@ export default class FormulaOneCard extends LitElement {
get properties() {
return this._cardValues;
}

private _cardValues?: Map<string, unknown>;

setConfig(config: FormulaOneCardConfig) {
setConfig(config: FormulaOneCardConfig) {

checkConfig(config);

this.config = { ...config };
}

Expand All @@ -65,28 +66,29 @@ export default class FormulaOneCard extends LitElement {
case FormulaOneCardType.ConstructorStandings:
this.card = new ConstructorStandings(this);
break;
case FormulaOneCardType.DriverStandings:
case FormulaOneCardType.DriverStandings:
this.card = new DriverStandings(this);
break;
case FormulaOneCardType.Schedule:
case FormulaOneCardType.Schedule:
this.card = new Schedule(this);
break;
case FormulaOneCardType.NextRace:
this.card = new NextRace(this);
break;
case FormulaOneCardType.LastResult:
case FormulaOneCardType.NextRace:
this.card = new NextRace(this);
break;
case FormulaOneCardType.LastResult:
this.card = new LastResult(this);
break;
case FormulaOneCardType.Countdown:
case FormulaOneCardType.Countdown:
this.card = new Countdown(this);
break;
case FormulaOneCardType.Results:
case FormulaOneCardType.Results:
this.card = new Results(this);
break;
}
}

static get styles(): CSSResult {
loadCustomFonts();
return styles;
}

Expand All @@ -96,7 +98,7 @@ export default class FormulaOneCard extends LitElement {
try {
return html`
<ha-card elevation="2">
${this.config.title ? html`<h1 class="card-header">${this.config.title}</h1>` : ''}
${this.config.title ? html`<h1 class="card-header${(this.config.f1_font ? ' formulaone-font' : '')}">${this.config.title}</h1>` : ''}
${this.card.render()}
</ha-card>
`;
Expand Down
11 changes: 7 additions & 4 deletions src/styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css } from 'lit';

export const styles = css`
export const styles = css`
table {
width: 100%;
border-spacing: 0;
Expand All @@ -15,7 +15,7 @@ export const styles = css`
text-align: left;
}
tr {
color: var(--secondary-text-color);
color: var(--secondary-text-color);
}
tr:nth-child(even) {
background-color: var(--table-row-alternative-background-color, #eee);
Expand All @@ -32,7 +32,7 @@ export const styles = css`
.width-60 {
width: 60px;
}
.hide {
.hide {
display: none;
}
.strikethrough {
Expand All @@ -43,7 +43,7 @@ export const styles = css`
}
a {
text-decoration: none;
color: var(--secondary-text-color);
color: var(--secondary-text-color);
}
.constructor-logo {
width: 20px;
Expand All @@ -57,4 +57,7 @@ export const styles = css`
.clickable {
cursor: pointer;
}
.formulaone-font {
font-family: 'F1Bold';
}
`;
1 change: 1 addition & 0 deletions src/types/formulaone-card-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface FormulaOneCardConfig extends LovelaceCardConfig {
translations?: Translation;
show_raceinfo?: boolean;
actions?: ActionOptions;
f1_font?: boolean;
}

export interface ActionOptions {
Expand Down
2 changes: 1 addition & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export const renderHeader = (card: BaseCard, race: Race, preventClick = false):
hasHold: hasAction(card.config.actions?.hold_action),
hasDoubleClick: hasAction(card.config.actions?.double_tap_action),
})} class="${(hasConfigAction ? ' clickable' : null)}" />`;
const raceName = html`<h2><img height="25" src="${getCountryFlagByName(race.Circuit.Location.country)}">&nbsp; ${race.round} : ${race.raceName}</h2>`;
const raceName = html`<h2 class="${(card.config.f1_font ? 'formulaone-font' : '')}"><img height="25" src="${getCountryFlagByName(race.Circuit.Location.country)}">&nbsp; ${race.round} : ${race.raceName}</h2>`;

return html`${(card.config.card_type == FormulaOneCardType.Countdown ? html`` : raceName)} ${imageHtml}<br>`;
}
Expand Down
17 changes: 9 additions & 8 deletions tests/cards/countdown.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('Testing countdown file', () => {
const { htmlResult, date } = await getHtmlResultAndDate(card);
jest.useRealTimers();

expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1></h1> </td> </tr> </table>');
expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2 class=""><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1 class=""></h1> </td> </tr> </table>');
expect(date.value).toMatch('19d 16h 0m 0s');
}),
test('Calling render with date equal to race start should render we are racing', async () => {
Expand All @@ -100,7 +100,7 @@ describe('Testing countdown file', () => {
const { htmlResult, date } = await getHtmlResultAndDate(card);
jest.useRealTimers();

expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1></h1> </td> </tr> </table>');
expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2 class=""><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1 class=""></h1> </td> </tr> </table>');
expect(date.value).toMatch('We are racing!');
}),
test('Calling render with date an hour past race start render we are racing', async () => {
Expand All @@ -116,7 +116,7 @@ describe('Testing countdown file', () => {
const { htmlResult, date } = await getHtmlResultAndDate(card);
jest.useRealTimers();

expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1></h1> </td> </tr> </table>');
expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2 class=""><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1 class=""></h1> </td> </tr> </table>');
expect(date.value).toMatch('We are racing!');
}),
test('Calling render with date an day past race start render we are racing', async () => {
Expand All @@ -127,7 +127,7 @@ describe('Testing countdown file', () => {
const { htmlResult, date } = await getHtmlResultAndDate(card);
jest.useRealTimers();

expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2><img height="25" src="https://flagcdn.com/w40/sa.png">&nbsp;&nbsp; 2 : Saudi Arabian Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1></h1> </td> </tr> </table>');
expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class=""> <tr> <td> <h2 class=""><img height="25" src="https://flagcdn.com/w40/sa.png">&nbsp;&nbsp; 2 : Saudi Arabian Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1 class=""></h1> </td> </tr> </table>');
expect(date.value).toMatch('6d 18h 0m 0s');
}),
test('Calling render with date end of season', async () => {
Expand Down Expand Up @@ -159,14 +159,14 @@ describe('Testing countdown file', () => {
}),
test('Calling renderheader with date end of season', async () => {

config.show_raceinfo = true;
config.show_raceinfo = true;
card.config = config;

const result = card.renderHeader(race);
const htmlResult = await getRenderStringAsync(result);
jest.useRealTimers();

expect(htmlResult).toMatch('<table><tr><td colspan="5"><h2><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp; 22 : Season is over. See you next year!</h2><img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/Bahrain_Circuit.png.transform/7col/image.png" @action=_handleAction .actionHandler= class="" /></td></tr> </table>');
expect(htmlResult).toMatch('<table><tr><td colspan="5"><h2 class=""><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp; 22 : Season is over. See you next year!</h2><img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/Bahrain_Circuit.png.transform/7col/image.png" @action=_handleAction .actionHandler= class="" /></td></tr> </table>');
}),
test('Calling renderheader with date end of season', async () => {

Expand Down Expand Up @@ -194,6 +194,7 @@ describe('Testing countdown file', () => {

const spy = jest.spyOn(customCardHelper, 'handleAction');

card.config.f1_font = true;
card.config.actions = {
tap_action: {
action: 'navigate',
Expand All @@ -215,7 +216,7 @@ describe('Testing countdown file', () => {
const { htmlResult, date, handleAction } = await getHtmlResultAndDate(card);
jest.useRealTimers();

expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class="clickable"> <tr> <td> <h2><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1></h1> </td> </tr> </table>');
expect(htmlResult).toMatch('<table @action=_handleAction .actionHandler= class="clickable"> <tr> <td> <h2 class="formulaone-font"><img height="25" src="https://flagcdn.com/w40/bh.png">&nbsp;&nbsp; 1 : Bahrain Grand Prix</h2> </td> </tr> <tr> <td class="text-center"> <h1 class="formulaone-font"></h1> </td> </tr> </table>');
expect(date.value).toMatch('19d 16h 0m 0s');

// eslint-disable-next-line @typescript-eslint/ban-types
Expand All @@ -235,7 +236,7 @@ async function getHtmlResultAndDate(card: Countdown) {
const promise = (result.values[0] as HTMLTemplateResult).values[0] as Promise<HTMLTemplateResult>;
const promiseResult = await promise;

const iterator = (promiseResult.values[6] as HTMLTemplateResult).values[0] as AsyncIterableIterator<HTMLTemplateResult>;
const iterator = (promiseResult.values[8] as HTMLTemplateResult).values[0] as AsyncIterableIterator<HTMLTemplateResult>;
// eslint-disable-next-line @typescript-eslint/ban-types
const handleAction = promiseResult.values[0] as Function;

Expand Down
Loading

0 comments on commit 9865b4f

Please sign in to comment.