Skip to content

Commit

Permalink
feat(cxl-ui): add cxl-course-card component
Browse files Browse the repository at this point in the history
  • Loading branch information
freudFlintstone committed Jul 14, 2023
1 parent d30c005 commit 8ee219c
Show file tree
Hide file tree
Showing 12 changed files with 555 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/cxl-lumo-styles/src/icons.js

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

235 changes: 235 additions & 0 deletions packages/cxl-ui/scss/cxl-course-card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
@use "~@conversionxl/cxl-lumo-styles/scss/mq";

:host {
display: flex;
position: relative;
height: max-content;
box-sizing: border-box;
min-height: 300px;
font-size: var(--lumo-font-size-s);
padding: var(--lumo-space-m) var(--lumo-space-l);
background: var(--lumo-tint);
border: 1px solid var(--lumo-contrast-10pct);
border-radius: var(--lumo-border-radius-l);
box-shadow: var(--lumo-box-shadow-xs);
break-inside: avoid;
transform: translateZ(0); // CSS columns @see https://stackoverflow.com/a/55110789/35946

// @see https://github.com/conversionxl/aybolit/pull/293
--video-background: hsla(355.8, 74.7%, 48%, 0.03); // --lumo-primary-color-3pct does not exist
--training-background: hsla(0, 0%, 10%, 0.03); // --lumo-shade-3pct does not exist
--playbook-background: hsla(213, 100%, 62%, 0.03); // No similar base color exists

// Container / Media queries
@media #{mq.$small} {
.container > .attributes {
display: none;
}

header .info .attributes {
display: flex;
}
}
}

:host(:hover) {
border-color: var(--lumo-primary-color);
}

:host([hidden]) {
display: none;
}

:host(:first-child) {
margin-top: unset;
}

:host(:last-child) {
margin-bottom: unset;
}

:host([theme~="dark"]) {
background-color: var(--lumo-contrast);
}

:host {
[empty] {
user-select: none;
visibility: hidden;
}
}

:host([theme~="video"]) {
background-color: var(--video-background);
}

:host([theme~="training"]) {
background-color: var(--training-background);
}

:host([theme~="playbook"]) {
background-color: var(--playbook-background);
}

.container {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: var(--lumo-space-s);
width: 100%;

> .attributes {
padding-top: 0;
}
}

.attributes {
display: flex;
padding: var(--lumo-space-s) 0;
align-items: flex-start;
gap: var(--lumo-space-s);
align-self: stretch;
color: var(--lumo-shade-60pct);
}

header {
display: flex;
align-items: start;
justify-content: space-between;
gap: var(--lumo-space-m);

.info {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--lumo-space-xs);
flex: 1 0 0;
align-self: stretch;
max-width: calc(100% - var(--lumo-space-m) - 80px);
overflow: hidden;

.title {
color: #1A1A1A;
font-size: var(--lumo-font-size-xl);
font-family: Roboto;
font-style: normal;
font-weight: 700;
line-height: var(--lumo-line-height-xs);
}

.attributes {
display: none;
}
}


.instructor-image {
height: 92px;
width: 80px;

img {
height: 80px;
border-radius: 100px;
overflow: hidden;
}
}

.tags span {
&:first-child, &.new {
color: var(--lumo-primary-color)
}

&:first-child {
text-transform: capitalize;
}
}
}

.tags {
display: flex;
gap: var(--lumo-space-s);
max-width: 100%;
overflow: hidden;
flex-wrap: wrap;
height: 1.6em;

::slotted(span):not(:first-child) {
overflow: hidden;
text-overflow: ellipsis;
}
}

.content {
.tags {
::slotted(span) {
font-style: italic;
}
}
}

footer {
position: relative;

vaadin-details[theme="reverse"] {
&::part(summary) {
justify-content: flex-start;
gap: var(--lumo-space-s);
font-size: var(--lumo-font-size-s);
}

&::part(toggle) {
padding: calc(var(--lumo-space-xs) / 4);
margin-left: initial;
font-size: var(--lumo-font-size-m);
transform: rotate(90deg);
}

&[opened]::part(toggle) {
transform: rotate(-90deg);
}

&::part(summary-content) {
color: var(--lumo-contrast);
font-weight: bold;
}

&::part(content) {
padding-bottom: 0;
}
}

vaadin-button.cta {
position: absolute;
top: 0;
right: 0;
font-weight: bold;

vaadin-icon {
background: var(--lumo-primary-color-10pct);
border-radius: 100%;
margin-left: var(--lumo-space-xs);
height: var(--lumo-icon-size-s);
width: var(--lumo-icon-size-s);
padding: calc(var(--lumo-space-xs) / 2);
}
}
}

vaadin-icon.badge-new {
display: none;
}

:host([new]) {
vaadin-icon.badge-new {
display: block;
position: absolute;
top: calc(-1 * var(--lumo-space-s));
right: calc(-1 * var(--lumo-space-s));
height: calc(2 * var(--lumo-space-m));
width: calc(2 * var(--lumo-space-m));
background: var(--lumo-primary-color);
padding: 6px;
color: var(--lumo-primary-contrast-color);
border-radius: 100%;
}
}
102 changes: 102 additions & 0 deletions packages/cxl-ui/src/components/cxl-course-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* eslint-disable import/no-extraneous-dependencies */
import { LitElement, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import '@vaadin/details';
import '@vaadin/button';
import cxlCourseCardStyles from '../styles/cxl-course-card-css.js';

@customElement('cxl-course-card')
export class CXLCourseCardElement extends LitElement {
static get styles() {
return [cxlCourseCardStyles];
}

separator = html`<span> | </span>`;

@state() _tagsHasChildren = false;

@state() _moreHasChildren = false;

@property({ type: String }) id = '';
@property({ type: String }) theme = 'course';
@property({ type: String }) title = '';
@property({ type: String }) time = '';
@property({ type: String }) instructor = '';
@property({ type: String }) avatar = '';
@property({ type: Boolean, reflect: true }) new = false;
@property({ type: String, attribute: 'cta-label' }) ctaLabel = 'View';
@property({ type: Boolean, attribute: 'cta-url' }) ctaUrl = false;
_slotHasChildren (e) {
const slot = e.target
const { name } = slot
const children = slot.assignedNodes()
this[`_${name}HasChildren`] = !!children.length
}
render() {
return html`
<div class="container">
<header>
<div class="info">
<div class="tags">
${this.theme ? html`<span>${this.theme}</span>`: ''}
${this.theme && this._tagsHasChildren ? this.separator : ''}
<slot name="tags" @slotchange=${this._slotHasChildren}></slot>
${this.new ? html`${this.theme ? this.separator : ''}<span class="new">NEW</span>` : '' }
</div>
<div class="title">
${this.title}
</div>
<div class="attributes">
<div class="time">
${this.theme.toLowerCase() === 'course' ? html`<vaadin-icon icon="lumo:clock"></vaadin-icon>` : ''}
${this.time}
</div>
<div class="instructor">
By: ${this.instructor}
</div>
</div>
</div>
<div class="instructor-image">
<img
src=${this.avatar}
alt="${this.instructor}"
/>
</div>
</header>
<div class="attributes">
<div class="time">
${this.theme.toLowerCase() === 'course' ? html`<vaadin-icon icon="lumo:clock"></vaadin-icon>` : ''}
${this.time}
</div>
<div class="instructor">
By: ${this.instructor}
</div>
</div>
<section class="content">
<slot name="content"></slot>
<div class="tags">
<slot name="content-tags"></slot>
</div>
</section>
<footer>
<vaadin-details theme="reverse" ?empty=${!this._moreHasChildren}>
<div slot="summary">Read more</div>
<slot name="more" @slotchange=${this._slotHasChildren}></slot>
</vaadin-details>
<vaadin-button class="cta" theme="tertiary">${this.ctaLabel} ${this.theme}<vaadin-icon icon="lumo:angle-right"></vaadin-icon> </vaadin-button>
</footer>
<vaadin-icon class="badge-new" icon="cxl:new"></vaadin-icon>
</div>
`;
}
}
1 change: 1 addition & 0 deletions packages/cxl-ui/src/index-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as Headroom from 'headroom.js';
// CXL.
export { CXLAppLayoutElement } from './components/cxl-app-layout.js';
export { CXLCardElement } from './components/cxl-card.js';
export { CXLCourseCardElement } from './components/cxl-course-card.js';
export { CXLCredentialElement } from './components/cxl-credential.js'
export { CXLCheckoutDetailsElement } from './components/cxl-checkout-details.js';
export { CXLMarketingNavElement } from './components/cxl-marketing-nav.js';
Expand Down
1 change: 1 addition & 0 deletions packages/cxl-ui/src/index-storybook.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as Headroom from 'headroom.js';

export { CXLAppLayoutElement } from './components/cxl-app-layout.js';
export { CXLCardElement } from './components/cxl-card.js';
export { CXLCourseCardElement } from './components/cxl-course-card.js';
export { CXLMarketingNavElement } from './components/cxl-marketing-nav.js';
export { CXLSectionElement } from './components/cxl-section.js';
export { CXLStatsElement } from './components/cxl-stats.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CourseCardTemplate, args } from './template.js'
import '@conversionxl/cxl-ui/src/components/cxl-course-card.js';
import '@conversionxl/cxl-lumo-styles';

export default {
title: 'CXL UI/cxl-course-card',
parameters: {
layout: 'centered'
}
};


export const CXLCourseCard = CourseCardTemplate.bind({});

CXLCourseCard.args = args;
Loading

0 comments on commit 8ee219c

Please sign in to comment.