import { LitElement, html, css } from 'lit'; import { property } from 'lit/decorators.js'; export class Card extends LitElement { @property({ type: Boolean }) raised = false; @property({ type: String }) variant: 'elevation' | 'outlined' = 'elevation'; @property({ type: Number }) elevation = 1; static styles = css` :host { display: block; font-family: "Roboto", "Helvetica", "Arial", sans-serif; } .card { background-color: #fff; border-radius: 4px; overflow: hidden; transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; position: relative; } /* Elevation variant */ :host([variant="elevation"]) .card, :host(:not([variant])) .card { box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12); } :host([raised]) .card { box-shadow: 0px 3px 3px -2px rgba(0,0,0,0.2), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12); } /* Outlined variant */ :host([variant="outlined"]) .card { box-shadow: none; border: 1px solid rgba(0, 0, 0, 0.12); } /* Elevation levels */ :host([elevation="0"]) .card { box-shadow: none; } :host([elevation="1"]) .card { box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12); } :host([elevation="2"]) .card { box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12); } :host([elevation="3"]) .card { box-shadow: 0px 3px 3px -2px rgba(0,0,0,0.2), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12); } :host([elevation="4"]) .card { box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12); } /* Hover effects for interactive cards */ :host([clickable]) .card { cursor: pointer; transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; } :host([clickable]) .card:hover { box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12); transform: translateY(-1px); } :host([clickable][variant="outlined"]) .card:hover { box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12); } `; render() { return html`
`; } } export class CardHeader extends LitElement { @property({ type: String }) title = ''; @property({ type: String }) subheader = ''; static styles = css` :host { display: block; padding: 16px 16px 0; } .header { display: flex; align-items: flex-start; flex-direction: column; } .header-content { display: flex; align-items: center; width: 100%; } .text-content { flex: 1; min-width: 0; } .title { font-size: 1.25rem; font-weight: 500; line-height: 1.6; letter-spacing: 0.0075em; margin: 0; color: rgba(0, 0, 0, 0.87); } .subheader { font-size: 0.875rem; font-weight: 400; line-height: 1.43; letter-spacing: 0.01071em; margin: 0; color: rgba(0, 0, 0, 0.6); margin-top: 4px; } ::slotted([slot="avatar"]) { margin-right: 16px; } ::slotted([slot="action"]) { margin-left: auto; align-self: flex-start; } `; render() { return html`
${this.title ? html`

${this.title}

` : ''} ${this.subheader ? html`

${this.subheader}

` : ''}
`; } } export class CardMedia extends LitElement { @property({ type: String }) src = ''; @property({ type: String }) alt = ''; @property({ type: String }) component: 'img' | 'video' | 'div' = 'img'; @property({ type: String }) height = '140px'; static styles = css` :host { display: block; position: relative; background-size: cover; background-repeat: no-repeat; background-position: center; } .media { width: 100%; object-fit: cover; display: block; } .media-div { width: 100%; background-size: cover; background-repeat: no-repeat; background-position: center; } ::slotted(*) { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; color: white; text-shadow: 0 1px 3px rgba(0,0,0,0.5); } `; updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('height')) { this.style.height = this.height; } if (changedProperties.has('src') && this.component === 'div') { this.style.backgroundImage = `url(${this.src})`; } } render() { if (this.component === 'img') { return html` ${this.alt} `; } if (this.component === 'video') { return html` `; } return html`
`; } } export class CardContent extends LitElement { static styles = css` :host { display: block; padding: 16px; } :host(:last-child) { padding-bottom: 24px; } `; render() { return html``; } } export class CardActions extends LitElement { @property({ type: Boolean }) disableSpacing = false; static styles = css` :host { display: flex; align-items: center; padding: 8px; box-sizing: border-box; } :host(:not([disableSpacing])) ::slotted(*) { margin-left: 8px; } :host(:not([disableSpacing])) ::slotted(*:first-child) { margin-left: 0; } ::slotted([slot="right"]) { margin-left: auto; } `; render() { return html` `; } }