import { classMap } from 'lit/directives/class-map.js' import { ifDefined } from 'lit/directives/if-defined.js' import { customElement, property } from 'lit/decorators.js' import { html, nothing } from 'lit' import { IPktTag } from '@/components/tag' import { PktElementWithSlot } from '@/base-elements/element-with-slot' import { slotContent } from '@/directives/slot-content' import { IPktHeading } from '../heading' import specs from 'componentSpecs/card.json' import '@/components/icon' /* eslint-disable no-duplicate-imports -- There's a different between the import methods */ import '@/components/tag' import '@/components/heading' import type { IAriaAttributes, TCardSkin, TLayout } from 'shared-types' export type { TCardSkin, TLayout } export type TCardPadding = 'none' | 'default' export type TCardImageShape = 'square' | 'round' export type TCardTagPosition = 'top' | 'bottom' export interface IPktCard { ariaLabel?: IAriaAttributes['aria-label'] metaLead?: string | null metaTrail?: string | null layout?: TLayout heading?: string headingLevel?: IPktHeading['level'] image?: { src: string; alt: string } imageShape?: TCardImageShape clickCardLink?: string | null openLinkInNewTab?: boolean | null borderOnHover?: boolean | null padding?: TCardPadding skin?: TCardSkin subheading?: string tagPosition?: TCardTagPosition tags?: (Omit & { text: string })[] } export class PktCard extends PktElementWithSlot implements IPktCard { // Properties @property({ type: String }) ariaLabel: string = '' @property({ type: String }) metaLead: string | null = null @property({ type: Boolean }) borderOnHover: boolean = true @property({ type: String, reflect: true }) clickCardLink: IPktCard['clickCardLink'] = null @property({ type: String }) metaTrail: string | null = null @property({ type: String }) layout: TLayout = specs.props.layout.default as TLayout @property({ type: String }) heading: string = '' @property({ type: Number }) headinglevel: IPktHeading['level'] = 3 @property({ type: Object }) image: { src: string; alt: string } = { src: '', alt: '', } @property({ type: String }) imageShape: TCardImageShape = 'square' @property({ type: Boolean }) openLinkInNewTab: boolean = false @property({ type: String }) padding: TCardPadding = specs.props.padding.default as TCardPadding @property({ type: String, converter: { fromAttribute: (value: string | null): TCardSkin => { const validSkins = specs.props.skin.type as TCardSkin[] if (value && validSkins.includes(value as TCardSkin)) { return value as TCardSkin } else { if (value && !validSkins.includes(value as TCardSkin)) { console.warn( `Invalid skin value "${value}". Using default skin "${specs.props.skin.default}".`, ) } return specs.props.skin.default as TCardSkin } }, toAttribute: (value: TCardSkin): string => value, }, }) skin: TCardSkin = specs.props.skin.default as TCardSkin @property({ type: String }) subheading: string = '' @property({ type: String }) tagPosition: 'top' | 'bottom' = 'top' @property({ type: Array }) tags: (Omit & { text: string })[] = [] connectedCallback() { super.connectedCallback() } // Render methods // Main render method // prettier-ignore render() { const classes = { 'pkt-card': true, [`pkt-card--${this.skin}`]: this.skin, [`pkt-card--${this.layout}`]: this.layout, [`pkt-card--padding-${this.padding}`]: this.padding, [`pkt-card--border-on-hover`]: this.borderOnHover, } // const ariaLabelLenke = this.ariaLabel?.trim() || (this.heading ? `${this.heading} lenkekort` : 'lenkekort') const ariaLabelVanlig = this.ariaLabel?.trim() || (this.heading ? this.heading : 'kort') return html`
${this.renderImage()}
${this.tagPosition === 'top' ? this.renderTags() : nothing} ${this.renderHeader()} ${this.renderSlot()} ${this.tagPosition === 'bottom' ? this.renderTags() : nothing} ${this.renderMetadata()}
` } // Render methods for different parts of the card renderImage() { const imageClasses = { 'pkt-card__image': true, [`pkt-card__image-${this.imageShape}`]: this.imageShape, } return html` ${this.image.src && html`
${this.image.alt
`} ` } // Do not render heading if link is present, render link heading instead // Combine the rendering for headings into a renderHeader method renderHeading() { return html` ${this.heading && !this.clickCardLink ? html` ${this.heading} ` : nothing} ` } renderLinkHeading() { return html` ${this.clickCardLink ? html` ${this.heading} ` : nothing} ` } renderSubheading() { return html` ${this.subheading ? html`

${this.subheading}

` : nothing} ` } // Render header // prettier-ignore renderHeader() { const hasHeading = !!this.heading || !!this.subheading return html` ${hasHeading ? html`
${this.renderHeading()} ${this.renderLinkHeading()} ${this.renderSubheading()}
` : nothing} ` } renderTags() { const tagClasses = { 'pkt-card__tags': true, [`pkt-card__tags-${this.tagPosition}`]: this.tagPosition, } return html` ${this.tags.length > 0 ? html`
1 ? 'merkelapper' : 'merkelapp'} > ${this.tags.map( (tag) => html` ${tag.text} `, )}
` : nothing} ` } renderSlot() { return html`
${slotContent(this)}
` } renderMetadata() { return html` ${this.metaLead || this.metaTrail ? html`
${this.metaLead ? html`` : nothing} ${this.metaTrail ? html`` : nothing}
` : nothing} ` } } try { customElement('pkt-card')(PktCard) } catch (e) { console.warn('Forsøker å definere , men den er allerede definert') }