Skip to content

Commit

Permalink
feat(cc-zone-card): init component
Browse files Browse the repository at this point in the history
  • Loading branch information
Galimede committed Oct 9, 2024
1 parent d9948ee commit ca935db
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 0 deletions.
184 changes: 184 additions & 0 deletions src/components/cc-zone-card/cc-zone-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { css, html, LitElement } from 'lit';
import { iconRemixCheckboxCircleFill as selectedIcon } from '../../assets/cc-remix.icons.js';
import { i18n } from '../../translations/translation.js';
import '../cc-icon/cc-icon.js';
import '../cc-img/cc-img.js';

/**
* @typedef {import('./cc-zone-card.types.js').ZoneImage} ZoneImage
*/

/**
* A component displaying a card with relative zone information (name, code...)
*
* @cssdisplay flex
*/
export class CcZoneCard extends LitElement {
static get properties() {
return {
code: { type: String },
country: { type: String },
countryCode: { type: String, attribute: 'country-code' },
disabled: { type: Boolean, reflect: true },
flagUrl: { type: String, attribute: 'flag-url' },
images: { type: Array },
name: { type: String },
selected: { type: Boolean, reflect: true },
};
}

constructor() {
super();

/** @type {string} The zone code */
this.code = null;

/** @type {string} The country name */
this.country = null;

/** @type {string} The ISO 3166-1 alpha-2 country code (e.g: FR) */
this.countryCode = null;

/** @type {boolean} Whether the card should be disabled */
this.disabled = false;

/** @type {string} The url of the flag image */
this.flagUrl = null;

/** @type {ZoneImage[]} A list of images that will displayed in the footer */
this.images = [];

/** @type {string} The name of the zone */
this.name = null;

/** @type {boolean} Whether the card should be selected */
this.selected = false;
}

render() {
return html`
<div class="title">
<div class="zone-code">${this.code}</div>
<div class="zone-name">${this.name}</div>
</div>
<cc-icon class="icon-selected" .icon="${selectedIcon}" size="lg"></cc-icon>
<div class="thumbnails">
${this.flagUrl
? html`
<cc-img
class="flag"
src=${this.flagUrl}
a11y-name="${i18n('cc-zone-card.alt.country-name', {
code: this.countryCode,
name: this.country,
})}"
></cc-img>
`
: ''}
${this.images.map((image) => html`<cc-img src="${image.url}" a11y-name="${image.alt}"></cc-img>`)}
</div>
`;
}

static get styles() {
return [
// language=CSS
css`
:host {
border: 2px solid var(--cc-color-border-neutral);
border-radius: var(--cc-border-radius-default);
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
.title {
flex: 1 1 auto;
padding: 1em 1em 0.75em;
}
:host(:hover:not([disabled])) {
border-color: var(--cc-color-border-neutral-hovered);
}
:host(:not([selected], [disabled])) {
cursor: pointer;
}
:host([selected]) {
border-color: var(--cc-color-bg-primary);
}
:host([selected]) .title .zone-code {
color: var(--cc-color-text-primary-strong);
}
:host([selected]) .title .zone-name {
color: var(--cc-color-text-primary-strongest);
}
:host([selected]) .icon-selected {
display: block;
}
:host([selected]) .thumbnails {
background-color: var(--cc-color-bg-primary-weak);
}
:host([disabled]) {
border-color: var(--cc-color-border-neutral-disabled);
opacity: var(--cc-opacity-when-disabled);
}
:host([disabled]) .zone-code {
color: #fff;
}
:host([disabled]) .thumbnails cc-icon,
:host([disabled]) .thumbnails cc-img {
filter: grayscale(1);
}
.zone-code {
color: var(--cc-color-text-weak);
font-size: 0.875em;
line-height: 1.125;
padding-inline-start: 0.125em;
}
.zone-name {
font-size: 1.5em;
line-height: 1.125;
}
.icon-selected {
--cc-icon-color: var(--cc-color-bg-primary);
display: none;
position: absolute;
right: 0.5em;
top: 0.5em;
}
.thumbnails {
align-items: center;
background-color: var(--cc-color-bg-neutral);
display: inline-flex;
flex: 0 0 auto;
gap: 0.5em;
padding: 0.75em 1.125em;
}
.thumbnails > cc-img {
--cc-img-fit: contain;
height: 1.5em;
width: 1.5em;
}
`,
];
}
}

window.customElements.define('cc-zone-card', CcZoneCard);
102 changes: 102 additions & 0 deletions src/components/cc-zone-card/cc-zone-card.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { getFlagUrl } from '../../lib/remote-assets.js';
import { makeStory } from '../../stories/lib/make-story.js';
import './cc-zone-card.js';

export default {
tags: ['autodocs'],
title: '🛠 Creation Tunnel/<cc-zone-card>',
component: 'cc-zone-card',
};

const cleverIcon = new URL('../../stories/assets/clevercloud.svg', import.meta.url);

const conf = {
component: 'cc-zone-card',
};

/**
* @typedef {import('./cc-zone-card.js').CcZoneCard} CcZoneCard
*/

/** @type {Partial<CcZoneCard>} */
const DEFAULT_ITEM = {
code: 'par',
name: 'Paris',
selected: false,
images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
flagUrl: getFlagUrl('FR'),
countryCode: 'FR',
country: 'France',
};

/** @type {Partial<CcZoneCard>} */
const LONG_CODE = {
code: 'very-very-very-very-very-very-very-long-code',
name: 'Zone',
selected: false,
images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
flagUrl: getFlagUrl('FR'),
countryCode: 'FR',
country: 'France',
};

/** @type {Partial<CcZoneCard>} */
const LONG_NAME = {
code: 'code',
name: 'very-very-very-very-very-very-very-long-name',
selected: false,
images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
flagUrl: getFlagUrl('FR'),
countryCode: 'FR',
country: 'France',
};

/** @type {Partial<CcZoneCard>} */
const LONG_CODE_AND_NAME = {
code: 'very-very-very-very-very-very-very-long-code',
name: 'very-very-very-very-very-very-very-long-name',
selected: false,
images: [{ url: cleverIcon, alt: 'infra: Clever Cloud' }],
flagUrl: getFlagUrl('FR'),
countryCode: 'FR',
country: 'France',
};

export const defaultStory = makeStory(conf, {
items: [DEFAULT_ITEM],
});

export const disabled = makeStory(conf, {
items: [{ ...DEFAULT_ITEM, disabled: true }],
});

export const selected = makeStory(conf, {
items: [{ ...DEFAULT_ITEM, selected: true }],
});

export const longCode = makeStory(conf, {
items: [
{ ...LONG_CODE, style: 'width: 10em' },
{ ...LONG_CODE, style: 'width: 20em' },
{ ...LONG_CODE, style: 'width: 30em' },
LONG_CODE,
],
});

export const longName = makeStory(conf, {
items: [
{ ...LONG_NAME, style: 'width: 10em' },
{ ...LONG_NAME, style: 'width: 20em' },
{ ...LONG_NAME, style: 'width: 30em' },
LONG_NAME,
],
});

export const longCodeAndLongName = makeStory(conf, {
items: [
{ ...LONG_CODE_AND_NAME, style: 'width: 10em' },
{ ...LONG_CODE_AND_NAME, style: 'width: 20em' },
{ ...LONG_CODE_AND_NAME, style: 'width: 30em' },
LONG_CODE_AND_NAME,
],
});
11 changes: 11 additions & 0 deletions src/components/cc-zone-card/cc-zone-card.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-env node, mocha */

import { testAccessibility } from '../../../test/helpers/accessibility.js';
import { getStories } from '../../../test/helpers/get-stories.js';
import * as storiesModule from './cc-zone-card.stories.js';

const storiesToTest = getStories(storiesModule);

describe(`Component: ${storiesModule.default.component}`, function () {
testAccessibility(storiesToTest);
});
4 changes: 4 additions & 0 deletions src/components/cc-zone-card/cc-zone-card.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ZoneImage {
url: string | URL;
alt: string;
}
4 changes: 4 additions & 0 deletions src/translations/translations.en.js
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,10 @@ export const translations = {
'cc-zone.country': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
//#region cc-zone-card
'cc-zone-card.alt.country-name': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
//#region cc-zone-input
'cc-zone-input.error': `Something went wrong while loading zones.`,
'cc-zone-input.private-map-warning': `Private zones don't appear on the map.`,
Expand Down
4 changes: 4 additions & 0 deletions src/translations/translations.fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,10 @@ export const translations = {
'cc-zone.country': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
//#region cc-zone-card
'cc-zone-card.alt.country-name': /** @param {{code: string, name: string}} _ */ ({ code, name }) =>
getCountryName(lang, code, name),
//#endregion
//#region cc-zone-input
'cc-zone-input.error': `Une erreur est survenue pendant le chargement des zones.`,
'cc-zone-input.private-map-warning': `Les zones privées n'apparaissent pas sur la carte.`,
Expand Down

0 comments on commit ca935db

Please sign in to comment.