diff --git a/packages/cxl-lumo-styles/scss/badge.scss b/packages/cxl-lumo-styles/scss/badge.scss index 083ce7ae2..a2aa47ae0 100644 --- a/packages/cxl-lumo-styles/scss/badge.scss +++ b/packages/cxl-lumo-styles/scss/badge.scss @@ -12,6 +12,11 @@ background-color: var(--cxl-color-brand-blue); } +[theme~="badge"][theme~="tertiary"] { + color: var(--lumo-primary-contrast-color); + background-color: var(--cxl-color-dark-green); +} + .course-skills { [theme~="badge"] { margin-right: var(--lumo-space-s); diff --git a/packages/cxl-lumo-styles/scss/global.scss b/packages/cxl-lumo-styles/scss/global.scss index ae9549991..a40c0b6ee 100644 --- a/packages/cxl-lumo-styles/scss/global.scss +++ b/packages/cxl-lumo-styles/scss/global.scss @@ -13,6 +13,7 @@ html { --cxl-color-black-50pct: hsla(0, 0%, 0%, 0.5); --cxl-color-brand-blue: hsla(214, 61%, 25%, 1); --cxl-color-light-pink: hsl(353, 73%, 96%, 1); + --cxl-color-dark-green: hsl(148, 57%, 24%, 1); /** * Lumo Icons have a documented 4px "safe area" around them. Vaadin Icons don't, for unknown reasons. diff --git a/packages/cxl-ui/scss/cxl-light-card.scss b/packages/cxl-ui/scss/cxl-light-card.scss index 1dea00503..8d56abff9 100644 --- a/packages/cxl-ui/scss/cxl-light-card.scss +++ b/packages/cxl-ui/scss/cxl-light-card.scss @@ -1,68 +1,174 @@ +/* stylelint-disable value-no-vendor-prefix, property-no-vendor-prefix -- some of these are necessary for line-clamp implementation */ +@use "~@conversionxl/cxl-lumo-styles/scss/mq"; +@use "~@conversionxl/cxl-ui/scss/mixins"; + :host { - min-width: 267px; // 3col widths on 1400px - max-width: 300px; - height: auto; - min-height: calc(3 * var(--lumo-space-xl)); - padding: var(--lumo-space-m); - - .container > .attributes { - display: none; + position: relative; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: space-between; + width: 100%; + height: 100%; + min-height: 122px; + min-width: 267px; + padding: var(--lumo-space-m) var(--lumo-space-s) var(--lumo-space-s) var(--lumo-space-m); + font-size: var(--lumo-font-size-s); + 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 + overflow: hidden; +} + +:host([hidden]) { + display: none; +} + +:host(:hover) { + border-color: var(--lumo-primary-color); +} + +:host([portrait]) { + display: block; + width: 175px; + min-width: 0; + padding: 0; +} + +:host([completed]) { + opacity: 0.6; +} + +:host([theme~="minidegree"]) { + background-color: var(--lumo-contrast); +} + +.container { + display: flex; + justify-content: space-between; +} + +.badge-new { + position: absolute; + right: var(--lumo-space-s); + bottom: var(--lumo-space-s); + display: none; + padding: calc(var(--lumo-space-xs) / 2) var(--lumo-space-s); + font-size: var(--lumo-font-size-s); + font-weight: 700; + line-height: var(--lumo-line-height-s); + color: var(--lumo-primary-contrast-color); + border-radius: calc(var(--lumo-border-radius-l) * 6); + background: var(--lumo-primary-color); + z-index: 2; + + :host([new]) & { + display: block; } +} - header { - .info { - .name { - font-size: var(--lumo-font-size-m); - font-weight: 600; - } +header { + display: flex; + align-items: start; + flex-direction: column; + flex-grow: 1; + justify-content: space-between; + padding-right: 112px; // avatar width - .attributes { - display: flex; - flex-direction: column; - align-items: flex-start; - padding-top: var(--lumo-space-xs); - padding-bottom: 0; - gap: var(--lumo-space-xs); - } + :host([portrait]) & { + padding: var(--lumo-space-m) calc(var(--lumo-space-xs) * 3) 0 calc(var(--lumo-space-xs) * 3); + } - cxl-time { - margin-left: -3px; // to align with the instructor text - } + :host([theme~="minidegree"]) & { + justify-content: flex-start; + } + + .info { + display: flex; + flex-direction: column; + gap: var(--lumo-space-xs); + } + + .tag { + text-transform: capitalize; + + &:first-child { + color: var(--lumo-primary-color); } + } + + .name { + font-family: var(--lumo-font-family); + font-size: var(--lumo-font-size-m); + font-style: normal; + font-weight: 600; + line-height: var(--lumo-line-height-xs); + @include mixins.ellipsis-for-lines(2); - .instructor-image { - height: 80px; + :host([theme~="minidegree"]) & { + color: var(--lumo-tint); + } + + a { + color: var(--lumo-body-text-color); + text-decoration: none; + + &:hover { + text-decoration: underline; + } } } -} -:host([completed]) { - opacity: 0.6; + cxl-time { + margin-left: -3px; // to align with the instructor text + color: var(--lumo-shade); + opacity: .6; + + :host([theme~="minidegree"]) & { + color: var(--lumo-tint-40pct); + opacity: 1; + } + } [icon="lumo:checkmark"] { display: inline-block; margin-top: calc(var(--lumo-space-xs) * -1); color: var(--lumo-primary-color); } -} -::slotted(footer) { - display: flex; - flex-wrap: wrap; - gap: var(--lumo-space-xs); -} - -:host([theme~="minidegree"]) { - .name { - color: var(--lumo-primary-contrast-color); + .progress { + display: flex; + flex-direction: column; + justify-content: center; + font-size: var(--lumo-font-size-xs); + line-height: var(--lumo-line-height-s); + color: var(--lumo-body-text-color); } - .attributes { - color: var(--lumo-tint-40pct); + .instructor { + color: var(--lumo-shade); + opacity: .6; } +} - cxl-time { - margin-left: -3px; // to align with the instructor text - color: var(--lumo-tint-40pct); +::slotted([slot="badges"]) { + position: relative; + z-index: 1; +} + +.avatar { + position: absolute; + right: 0; + bottom: 0; + display: block; + width: 112px; + + :host([portrait]) & { + position: relative; + width: 100%; + margin-top: var(--lumo-space-s); } } diff --git a/packages/cxl-ui/src/components/cxl-light-card.js b/packages/cxl-ui/src/components/cxl-light-card.js index b916a8e0c..1fde425f2 100644 --- a/packages/cxl-ui/src/components/cxl-light-card.js +++ b/packages/cxl-ui/src/components/cxl-light-card.js @@ -1,17 +1,44 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { html, nothing } from 'lit'; +import { html, LitElement, nothing } from 'lit'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; -import { customElement, property } from 'lit/decorators.js'; -import '@conversionxl/cxl-lumo-styles'; +import { customElement, property, state } from 'lit/decorators.js'; + +import '@vaadin/progress-bar'; + import cxlLightCardStyles from '../styles/cxl-light-card-css.js'; -import { CXLBaseCardElement } from './cxl-base-card.js'; @customElement('cxl-light-card') -export class CXLLightCardElement extends CXLBaseCardElement { +export class CXLLightCardElement extends LitElement { static get styles() { - return [...super.styles, cxlLightCardStyles]; + return [cxlLightCardStyles]; } + separator = html` | `; + + @state() _tagsHasChildren = false; + + @property({ type: String }) id = ''; + + @property({ type: String }) theme = ''; + + @property({ type: String }) name = ''; + + @property({ type: String }) avatar = ''; + + @property({ type: String }) time = ''; + + @property({ type: String }) instructor = ''; + + @property({ type: Number }) progress = 0; + + @property({ type: Number }) lessons = 0; + + @property({ type: Boolean, reflect: true }) new = false; + + @property({ type: Boolean, reflect: true }) portrait = false; + + @property({ type: Boolean, reflect: true }) completed = false; + constructor() { super(); this.showTimeIcon = true; @@ -28,23 +55,116 @@ export class CXLLightCardElement extends CXLBaseCardElement { this.requestUpdate('showTags', this._showTags); } - _renderHeaderName() { + _slotHasChildren(e) { + const slot = e.target; + const { name } = slot; + const children = slot.assignedNodes(); + this[`_${name}HasChildren`] = !!children.length; + } + + _renderNew() { + return this.new ? html`NEW` : nothing; + } + + _renderTags() { + if (this.showTags) { + return html` +
+ `; + } + + return nothing; + } + + _renderName() { return html`